终端窗口大小不使用 ioctl 更新
Posted
技术标签:
【中文标题】终端窗口大小不使用 ioctl 更新【英文标题】:Terminal window size doesn't update using ioctl 【发布时间】:2018-02-01 17:50:30 【问题描述】:我在虚拟机中使用香草 Ubuntu。有问题的代码:
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
printf("lines %d\n", w.ws_row);
printf("columns %d\n", w.ws_col);
printf("\033[8;40;100t");
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
printf("lines %d\n", w.ws_row);
printf("columns %d\n", w.ws_col);
return 0;
当我编译并运行它时,会打印出原始终端窗口大小,然后将窗口大小调整为 40x100,但最后的 printf 行不反映新的终端窗口大小。
这里发生了什么,如何获取更新的终端窗口大小信息?
【问题讨论】:
【参考方案1】:您的代码中的一个问题很明显,在printf("\033[8;40;100t");
之后您还没有刷新stdout
。因此,当您调用第二个ioctl()
时,这些转义序列仍在stdout
的缓冲区中。
但是,即使您添加了fflush(stdout);
,结果也很可能没有变化。因为存在先调整窗口大小还是先调用下一个ioctl()
的竞争条件。即使添加tcdrain()
,情况仍然如此。
如果您为SIGWINCH
安装信号处理程序,则可以验证这一点。
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <string.h>
void winsz_handler(int sig)
const char *s = "winsize changed!\n";
write(STDOUT_FILENO, s, strlen(s));
int main(void)
signal(SIGWINCH, winsz_handler);
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
printf("lines %d\n", w.ws_row);
printf("columns %d\n", w.ws_col);
printf("\033[8;40;100t");
fflush(stdout);
tcdrain(STDOUT_FILENO);
// remove this comment, then it works on my machine
// However, it's ad hoc because there is no garantee
//usleep(100000);
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
printf("lines %d\n", w.ws_row);
printf("columns %d\n", w.ws_col);
sleep(1);
return 0;
“winsize changed”输出是最后一个。如果评论中的usleep()
被删除,那么它可以在我的机器上运行。当然,这不是一个很好的竞争条件解决方案。
【讨论】:
有几个函数不应该在信号处理程序中使用。printf()
是那些不应使用的函数之一。以上是关于终端窗口大小不使用 ioctl 更新的主要内容,如果未能解决你的问题,请参考以下文章