Author ====== Robert Clausecker Fraunhofer FOKUS (institute for open communication systems) Introduction ============ This proposal aims to standardize the broadly available signal SIGWINCH and an extension to termios to query and set the terminal window size. This extension is designed to be easily implementable in terms of the TIOCGWINSZ and TIOCSWINSZ ioctl() calls available on many UNIX-like systems. This proposal does not contain an extension to the stty utility as that is already considered in the scope of [bug 1053]. This proposal introduces new functions tcgetsize() and tcsetsize() instead of introducing the ioctl() calls TIOCGWINSZ and TIOCSWINSZ as POSIX generally does not standardize the ioctl() except for the STREAMS interface. [bug 1053]: http://austingroupbugs.net/view.php?id=1053 Compatibility Impact ==================== This extension defines a new macro SIGWINCH, a new structure winsize and two new functions tcgetsize() and tcsetsize(). The macro SIGWINCH is reserved in §2.2.2 for the header signal.h, the symbols are not reserved. The specification of the signal SIGWINCH and the winsize structure aims to follow historic practice. The specifications of tcgetsize() and tcsetsize() aim to be implementable as trivial wrappers over the common TIOCGWINSZ and TIOCSWINSZ ioctl() calls. It is intended that the specification of these functions is congruent to the historic behaviour of TIOCGWINSZ and TIOCSWINSZ. Extensions to termios.h ======================= A new subsection named "The winsize structure" is added to the header termios.h right after the section "The termios structure." The type "unsigned short" follows historical convention. Perhaps the comittee wishes to instead introduce appropriate integer types for the structure members instead. This might be useful for implementations aiming to support terminals with more than 65535 horizontal or vertical pixels. The winsize Structure --------------------- The header shall define the winsize structure, which shall include at least the following members: unsigned short ws_row rows, in characters. unsigned short ws_col columns, in characters. unsigned short ws_xpixel horizontal size, in pixels. unsigned short ws_ypixel vertical size, in pixels. In all members named in this volume of POSIX.1 2008, a value of 0 shall indicate that the value is unknown. Furthermore, the list of declared functions shall be amended with the following two entries: int tcgetsize(int, struct winsize *); int tcsetsize(int, const struct winsize *); The section "CHANGE HISTORY" shall be amended appropriately. Extensions to signal.h ====================== The table of signals shall be amended with the following entry: Signal: SIGWINCH Default Action: I Description: Window size changed. The entry shall be added immediately after the entry for SIGUSR1. The section "CHANGE HISTORY" shall be amended appropriately. Extensions to §2.4.3 Signal Actions =================================== The list of async-signal-safe functions shall be amended by the functions tcgetsize() and tcsetsize(). New function "tcgetsize" ======================== A new page "tcgetsize" shall be added to the list of system interfaces. Its text is analogous to that of tcgetattr and shall be as follows: NAME tcgetsize -- get the window size associated with a terminal SYNOPSIS #include int tcgetsize(int fildes, struct winsize *winsize_p); DESCRIPTION The tcgetsize() function shall get the window size associated with the terminal referred to by fildes and store them in the winsize structure pointed to by winsize_p. The fildes argument is an open file descriptor associated with a terminal. The winsize_p argument is a pointer to a winsize structure. It is implementation defined whether the window size associated with a terminal refers to the actual size and resolution of the terminal connected to the communication port associated with the terminal. The tcgetsize() operation is allowed from any process. RETURN VALUE Upon succesful completion, 0 shall be returned. Otherwise, -1 shall be returned and errno set to indicate the error. ERRORS The tcgetsize() function shall fail if: [EBADF] The fildes argument is not a valid file descriptor. [ENOTTY] The file associated with fildes is not a terminal. EXAMPLES The following example demonstrates how tcgetsize can be used in conjunction with a handler for SIGWINCH to keep track of the terminal window size associated with the standard error stream. #include #include #include #include static struct winsize ws; static void winch_handler(int signum) { (void)signum; if (tcgetsize(STDERR_FILENO, &ws) == -1) /* Handle error. */ } int main() { struct sigaction sa; sa.sa_handler = winch_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGWINCH, &sa, NULL); for (winch_handler(SIGWINCH); ; pause()) printf("row = %3d, col = %3d, xpixel = %4d, ypixel = %4d\n", ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel); } APPLICATION USAGE None. RATIONALE The tcgetsize() function is provided to allow applications to query the current size of a terminal window. This is necessary for applications intended to be run in terminal emulators whose window size can be changed at runtime. A SIGWINCH signal is delivered to a terminal's process group whenever its window size is changed. By installing a signal handler for SIGWINCH, a process can detect the resizing of its controlling terminal and take action, e.g. by redrawing its user interface to the new size. FUTURE DIRECTIONS None. SEE ALSO tcsetsize, The "CHANGE HISTORY" section shall be filled in appropriately. New function "tcsetsize" ======================== A new page "tcsetsize" shall be added to the list of system interfaces. Its text is analogous to that of tcsetattr and shall be as follows: NAME tcsetsize -- set the window size associated with a terminal SYNOPSIS #include int tcsetsize(int fildes, const struct winsize *winsize_p); DESCRIPTION The tcsetsize() function shall set the window size associated with the terminal referred to by the open file descriptor fildes (an open file descriptor associated with a terminal) from the winsize structure referenced by winsize_p. The change shall occur immediately. If the terminal size was changed succesfully, a SIGWINCH shall be delivered to the foreground process group associated with the terminal. If the terminal is a slave pseudo-terminal, a SIGWINCH shall also be delivered to the foreground process group of the associated master pseudo-terminal. Similarly, if the terminal is a master pseudo-terminal, a SIGWINCH shall be delivered to the foreground process group of the associated slave pseudo-terminal. No signal shall be delivered if the terminal size and resolution were changed to the same value they had before the tcsetsize() call. If the foreground process groups of master and slave pseudo-terminals are the same, only one SIGWINCH shall be delivered to the process group. If one of the mentioned foreground process groups does not exist, the corresponding signal shall not be delivered. The tcsetsize() function shall return successfully if it was able to alter the terminal size or resolution. It is implementation defined whether changing the window size of a terminal causes any changes in the size or resolution of the terminal emulator's graphical output. The effect of tcsetsize() is undefined if the value of the winsize structure pointed to by winsize_p was not derived from the result of a call to tcgetsize() on fildes; an application should only modify only fields defined by this volume of POSIX.1-2008 between the call to tcgetsize() and tcsetsize(), leaving all other fields unmodified. No actions defined by this volume of POSIX.1-2008, other than a call to tcsetsize(), a close of the last file descriptor in the system associated with this terminal device, or an open of the first file descriptor in the system associated with this terminal device (using the O_TTY_INIT flag if it is non-zero and the device is not a pseudo-terminal), shall cause any of the terminal attributes defined by this volume of POSIX.1-2008 to change. RETURN VALUE Upon successful completion, 0 shall be returned. Otherwise, -1 shall be returned and errno set to indicate the error. ERRORS The tcsetsize() shall fail if: [EBADF] The fildes argument is not a valid file descriptor. [EINVAL] An attempt was made to change an attribute represented in the winsize structure to an unsupported value. [ENOTTY] The file associated with fildes is not a terminal. EXAMPLES None. APPLICATION USAGE If the window of a graphical terminal emulator is resized, the terminal emulator should invoke tcsetsize() to relay the new window size and resolution to the slave's foreground process group. If a process attached to the slave of a graphical terminal emulator's pseudo-terminal calls tcsetsize(), the terminal emulator should attempt to change the window size and resolution to reflect the requested terminal size. RATIONALE None. FUTURE DIRECTIONS None. SEE ALSO tcgetsize, The "CHANGE HISTORY" section shall be filled in appropriately. New section §11.2.7 Window Size =============================== Immediately after §11.2.6 "Special Control Characters," a new section named "Window Size" shall be added with the following text: 11.2.7 Window Size Routines that need to query or set the terminal window size shall do so by using the winsize structure as defined in the header. Since the winsize structure may include additional members, the structure should never be initialized directly by the application as this may cause the terminal to behave in a non-conforming manner. When opening a terminal device (other than a pseudo-terminal) that is not already open in any process, it should be opened with the O_TTY_INIT flag before initializing the structure using tcgetsize() to ensure that any non-standard elements of the termios structure are set to values that result in conforming behavior of the terminal interface. The members of the winsize structure include (but are not limited to): +----------------+-------------+----------------------------+ | Member Type | Member Name | Description | +----------------+-------------+----------------------------+ | unsigned short | ws_row | rows, in characters | | unsigned short | ws_col | columns, in characters | | unsigned short | ws_xpixel | horizontal size, in pixels | | unsigned short | ws_ypixel | vertical size, in pixels | +----------------+-------------+----------------------------+ For each member, a value of 0 indicates that the size is unknown. A program can query the window size associated with a terminal using the tcgetsize() function and alter the window size using the tcsetsize() function. Updating the window size causes a SIGWINCH to be delivered to the terminal's foreground process group if any. It is implementation-defined whether the window size associated with a terminal actually corresponds to the physical size and resolution of the physical or virtual terminal device connected to the terminal's communication port. If it does correspond, changing the size or resolution of the terminal device causes a SIGWINCH to be sent to the foreground process group of the terminal.