终端 window 大小未使用 ioctl 更新
Terminal window size doesn't update using ioctl
我在 VM 中使用 vanilla 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("3[8;40;100t");
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
printf("lines %d\n", w.ws_row);
printf("columns %d\n", w.ws_col);
return 0;
}
当我编译 运行 时,原始终端 window 大小被打印出来,然后 window 被调整为 40x100,但最后的 printf 行没有反映新终端 window 大小。
这是怎么回事,我怎样才能获得更新的终端 window 尺寸信息?
您的代码中的一个问题很明显,在 printf("3[8;40;100t");
之后您还没有刷新 stdout
。因此,当您调用第二个 ioctl()
时,那些转义序列仍在 stdout
的缓冲区中。
但是,即使您添加 fflush(stdout);
,结果也很可能没有变化。因为存在先调整 window 大小还是先调用下一个 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("3[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()
被删除,那么它可以在我的机器上运行。当然,这不是竞争条件的好解决方案。
我在 VM 中使用 vanilla 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("3[8;40;100t");
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
printf("lines %d\n", w.ws_row);
printf("columns %d\n", w.ws_col);
return 0;
}
当我编译 运行 时,原始终端 window 大小被打印出来,然后 window 被调整为 40x100,但最后的 printf 行没有反映新终端 window 大小。
这是怎么回事,我怎样才能获得更新的终端 window 尺寸信息?
您的代码中的一个问题很明显,在 printf("3[8;40;100t");
之后您还没有刷新 stdout
。因此,当您调用第二个 ioctl()
时,那些转义序列仍在 stdout
的缓冲区中。
但是,即使您添加 fflush(stdout);
,结果也很可能没有变化。因为存在先调整 window 大小还是先调用下一个 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("3[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()
被删除,那么它可以在我的机器上运行。当然,这不是竞争条件的好解决方案。