5 ms·
The history of Unix's ioctl and signal about window sizes
- clausecker 2y agoI submitted the proposal for `tcgetwinsize` to POSIX a few years ago. I originally wrote it because I was sick of having to turn off _POSIX_C_SOURCE for just a single file to get glibc to expose TIOCGWINSZ. SIGWINCH and the TIOCGWINSZ ioctl() were originally omitted from POSIX as they were considered relevant for windowing systems only and GUI-stuff was considered out of scope for POSIX. Furthermore, POSIX only specifies ioctl() for STREAMS; other interfaces that traditionally use ioctl() calls are specified in POSIX using wrapper functions (which is what the new interface is; it is specified such that you can implement it just by wrapping the traditional TIOCGWINSZ/TIOCSWINSZ ioctl calls). My original proposal had functions tcgetsize() and tcsetsize(), but it turns out that QNX already uses these identifiers with an incompatible signature, so a last minute change was made to name these tcgetwinsize() and tcsetwinsize(). Furthermore, the winsize structure traditionally also has ws_xpixel and ws_ypixel members indicating the resolution of the terminal. This existed primarily becaus on some historical virtual terminals, a client could change the video mode by calling the TIOCSWINSZ ioctl, providing resolution and row/column count for the desired video mode. While no current virtual terminal known to me supports this, the POSIX spec mandates that if a slave PTY calls tcsetwinsize(), the window size update is propagated to the master, allowing terminal emulators to implement this feature if desired. Another objection raised was that the traditional unsigned short type may be insufficient for future high-definition screens and a resolution may not be well defined for some types of terminals like hardcopy or braille terminals. I maintain that submitting a feature to POSIX and waiting for a new version of the standard to be released is probably the easiest way to get glibc to implement a feature you want.
- aumerle 2y agoLots of modern terminals support ws_xpixel and ws_ypixel. Hell even the venerable xterm supports it. It is used primarily for displaying raster graphics in modern terminals, see for example: https://sw.kovidgoyal.net/kitty/graphics-protocol/#getting-the-window-size https://sw.kovidgoyal.net/kitty/graphics-protocol/#getting-t... And nowadays modern terminals even support in-band resize notification so there is no need for SIGWINCH: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83 https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3...
- clausecker 2y agoMy point was not that the terminals don't report ws_xpixel and ws_ypixel, but rather that none support the application setting the resolution using tcsetwinsize() with the terminal subsequently changing its video mode / resizing itself to the requested size.
- aumerle 2y agoAh yes, in that case there no terminals that implement it indeed. Though there are a few that implement changing window size via escape code, though in units of cells not pixels. Generally speaking I dont see how applications can use tcsetwinsize() robustly, given that the size in pixels of a cell is determined by font properties and applications runing in the terminal have no knowledge of these, therefore cannot set both the pixel and cell sizes at the same time.
- clausecker 2y agoCorrect, that was one of the concerns. Note that tcsetwinsize() is mainly provided so that the pty master (i.e. the terminal emulator) can set the window size to be seen by the slave (i.e. the application running in the emulated terminal). The other direction is not explicitly banned though.
- j4_james 2y agoFYI, there are a few terminals that can set the window size in pixels (with `CSI 4 t`). And it's also worth mentioning that there were already terminal emulators back in the 1980s that supported in-band resize notifications (lookup `VTEEWR` - Enable Window Event Reports).
- high_na_euv 2y ago>tcgetwinsize >_POSIX_C_SOURCE >TIOCGWINSZ >SIGWINCH >TIOCSWINSZ Jesus christ, this whole fashion among the C and linux people focused on writing shorter, but unreadable names is really terrible habbit
- wwalexander 2y agoI believe this stems from C originally only having 8 significant characters for identifiers.
- cesarb 2y agoNot only that, but screen space was really limited back then; it was not uncommon to develop on terminals with as low as 80 columns and 24 lines. Having shorter names meant more of the code could fit on the screen at the same time.
- rbanffy 2y agoThe limited size helps with keeping the code short and simple. ;-)
- kps 2y agoHistorically there was a bifurcation between scientific/technical computing and business computing. The former wanted to write something close to E = mc², while the latter wanted `MULTIPLY MASS-IN-GRAMS TIMES SPEED-OF-LIGHT-IN-A-VACUUM-IN-METERS-PER-SECOND TIMES SPEED-OF-LIGHT-IN-A-VACUUM-IN-METERS-PER-SECOND GIVING ENERGY-IN-JOULES`. With the dotcom boom, the last vestiges of the old republic were finally swept away, and now even C programmers get slapped for writing `c`.
- marssaxman 2y agoI still develop on a terminal with 80 columns, to this day! ...but it has 96 rows, and there are five of them, side by side across my monitor. Definitely an improvement! - but I still prefer not to have long rambling Java-style identifiers.
- ape4 2y agoI like this old Unix history stuff
- deleted 2y ago[deleted]
- TOGoS 2y agoOkay, but why is it a signal at all? In the end, isn't it just escape sequences sent back and forth in-band? Wouldn't it be simpler to just let the program read and write those rather than involving a separate system call?
- clausecker 2y agoA signal means that the application can immediately redraw its UI to the new dimension even if it is not currently reading input. Also, if the size was reported in-band, it would mess up applications that are not aware of that in-band signalling.
- thatcks 2y agoMy understanding is that the original SunOS windowing system was deeply connected to the kernel (for instance, windows were devices). The original purpose of the signal (in SunOS) appears to have been telling graphical programs that their window had 'changed' and needed to be repainted (I don't know if this was simply from resizing or if it was any damage), which makes a certain amount of sense for a kernel based windowing system (the kernel is right there and you need some way to notify programs). The use of the signal for telling programs in terminal windows that the window had resized appears to have been distinctly secondary, and only the latter can interact with their window through in-band escape sequences. (I'm the author of the linked-to article.)
- rockorager 2y agoExactly - these should be reported along with any other input event as an escape sequence. There are other comments on this post that link to how this is done.
- gomijacogeo 2y agoAs with everything tty related, there's a lot of history baked into the architecture. As new features arrive, you have to find some place in that architecture to insert it, perhaps awkwardly, but it beats rewriting the world. So we start the interactive age with teletypes, keyboards and paper. Nothing beyond printing the characters, ringing the bell, and the basic ACSII chars for moving right (SPACE, TAB), left (BS, CR), and down (VT, FF, LF). The main editor is a line editor called ed. Move ahead a few years and you have 'glass' ttys, every one of them different. This is the termcap and curses era. The screen size is baked into the termcap entry. Editors are now interactive 'screen' editors, vi and emacs mostly. Pretty soon, some terminals can support multiple font sizes and the LINES and COLUMNS environment variables can override the termcap entries. Terminals are still separate devices connected via RS-232 and all communication is in-band. Move ahead a few more years and we're now in the era of workstations with bitmapped graphics (and their Mac and PC equivalents). 'Terminals' are now interactive graphics programs that run under the window system (either X11 or proprietary), so they need to translate kbd and mouse events into the ASCII byte stream onto a pty to emulate the old RS-232 convention to talk to the "line dscipline" part of the kernel's tty driver. But now, changing the size of a window is trivial; people do it all the time. They do it in the middle of vi sessions. They do it when they've ^Z'd out of vi and then expect vi to know the new size when they fg back into it. You can't just blast escape codes onto the line as whatever is reading stdin is likely not equipped to deal with it. At the very least, the in-band exchange has to be initiated by the 'computer' side of the pty. So, they added SIGWINCH and it was an out-of-band signal sent from the terminal emulator program through the pty (which, again, is a software abstraction in the os as opposed to an RS-232 line) to tell the other side of the pty that, when it has a chance, it should re-query the size of the terminal. It took a little while to nail down the semantics of the shell notifying backgrounded processes, but it got the job done. But it likely doesn't make a lick of sense to anyone that doesn't remember the good ol' days.
- kevin_thibedeau 2y agoYou don't have to use the ioctl. The xterm escape code to query window size is widely supported across terminal emulators. It has the distinct advantage of working remotely and from non-unix systems.
- rockorager 2y agoThe single downside being you can get signals for SIGWINCH, while the (legacy) xterm escape sequence requires polling. I wrote a proposal[0] to have terminals send these updates in-band, instead of requiring polling a-la xterm. So far, foot, ghostty, iterm2, and kitty have implemented this feature on the terminal side. Neovim, notably, also supports this on the client side. [0]: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83 https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3...
- clausecker 2y agoThis stuff sucks because if the application forgets to turn it back off, the terminal pukes random control characters into your shell every time the window is resized.
- mrlonglong 2y agoThat's what `reset` is so useful for.
- caf 2y agoThe ioctl works remotely as well, because ssh sends window size messages across the channel.
- kevin_thibedeau 2y agoTerminals still run over raw serial ports.
- klysm 2y agoTerminals, ttys, etc. have some of the most arcane and outdated APIs I am aware of. It's like a window back into the 1970s
- ggm 2y agoThe window part is 1980s. the window back is deeper than the 70s, because the termcap/terminfo specs go into Teletype ASR33 territory which is 70s implementations of a core technology from the Baudot code era.
- wpm 2y agoIt's one of the reasons I love them. A ball of insane, esoteric, baffling, confusing cruft, layered in a century long onion, with connections to the very basics of telecommunications. At any moment, both the simplest interface and the most complex, both the beautiful speckled black void of the night sky, and the horrific gaping maw of a Lovecraftian beast.
- amelius 2y agoHow do you constrain the window size of a terminal?
- ggm 2y agoSignal handling demands constraints in how much you do. I never enjoyed coding to unix signals, I always wound up finding a new way to trample on that state you assume is clean, but inside the sig handler it turns out things are not what you think sometimes. The manual page used to be pretty explicit: do as little as humanly possible inside this execution context. I am probably mis-remembering but my memory is getting a signal while handling another signal was a point of pain.
- amiga386 2y agoFor anybody wondering "why couldn't they just...", there is a lot of complexity in TTYs and PTYs. The kernel is even involved in line discipline and job control. Those Ctrl+Z or Ctrl+C keys you press? The kernel gets involved. It may seem strange that there's a process signal for window-size changes, but that's what was needed back in 1985. There's a similar dance with the Amiga's console.device, but both Unix and Amiga TTYs are better than Windows' terminals where there was no such thing as a PTY until Windows 10, you had to make direct API calls, and even now it's still pretty slow: https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ https://devblogs.microsoft.com/commandline/windows-command-l... This page is a great overview pf the Unix TTY/PTY subsystem: https://www.linusakesson.net/programming/tty/ https://www.linusakesson.net/programming/tty/
- rbanffy 2y agoI have conflicting feelings abou This. The OS should not be concerned by this kind of thing. This is completely in the realm of the shell and many physical could change the number of rows or columns either on user command via its settings or through the host sending an equivalent command. This does not belong into a kernel.
- emmelaich 2y agoYou're not alone, and this is why plan9 has only 51 syscalls instead of the hundreds for Linux/BSD/... and thousands for Windows.
- akira2501 2y agoIt's just a driver. Do you feel the same about pipe(4)? As effectively that's mostly what PTYs have become.
- rbanffy 2y agoThe kernel should never need to concern itself with the nature of what is sending or receiving a stream of bytes.