我所知道的是,进程默认将文件描述符 0/1 设置为 stdin/stdout。但是像vi这样的程序如何知道窗口大小,特别是当我可以在桌面环境中自由调整窗口大小时?我想不出这是如何通过信号发送的,所以我猜还有其他一些机制?
我对终端模拟器一无所知,我想这可能与这个问题有关。任何指示都会有所帮助和赞赏。
答案1
终端的大小保存在内核内部结构中,可以通过ioctl 查询TIOCGWINSZ
和设置TIOCSWINSZ
。有关详细信息,请参阅ioctl_tty(2)
联机帮助页。
每次通过设置窗口大小TIOCSWINSZ
(例如,xterm
调整 GUI 窗口大小时),内核都会SIGWINCH
向前台进程组该终端的。
像这样的程序vi
捕获该信号并通过 更新其窗口大小的想法TIOCGWINSZ
。
窗口大小通常由驱动伪 tty 主端的程序(如xterm
或sshd
)设置,但任何能够打开 tty 的进程(无论是只读还是只写模式)都可以做到这一点。
这些 ioctl 的命令行界面是通过stty
程序实现的。 (例如stty cols 80 rows 40
)。这对于真正的串行终端非常有用,这些终端没有固有的大小,也没有传递该信息的标准方法。
虽然尚未标准化[1],所有这些都不是特定于 Linux 的,并且在 BSD 或 Solaris 等其他系统上的工作方式类似。一个显着的区别是背景尝试更改其控制 tty 大小的进程将在 BSD 和 Solaris 上TIOCSWINSZ
收到信号,但在 Linux 上则不会。SIGTTOU
在任何这些系统上,背景进程不会收到SIGWINCH
信号,无论是在调整其控制 tty 大小时,还是在它成为前台进程时。全屏程序假定它们要么在前台运行,要么已停止,并且还会根据SIGCONT
信号查询终端大小(以及其他 tty 操作,例如切换到备用屏幕或关闭规范模式)。
请注意,进程不需要拥有 tty 的打开句柄才能成为其控制 tty,并且它可以拥有 tty 的打开句柄而不成为其控制 tty。
除了进入 tty 的前台进程组之外,没有其他方法可以通知进程终端大小的变化。此外,没有通用的方式来通知其他对终端参数的更改:tcsetattr(3)
不会生成任何可以select(2)
编辑的信号或事件。
[1]标准接口预计将包含在即将推出的 POSIX 版本中,其中包含tcgetwinsize
和tcsetwinsize
函数,可轻松实现为ioctl(TIOC[SG]WINSZ)
.看这里了解详情。