1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 //! Unix implementation of `tutil::screen`, should work on Linux, FreeBSD and OS X.
7 use super::{Width, Height};
9 use std::os::raw::c_ushort;
10 use libc::{ioctl, isatty, STDOUT_FILENO, TIOCGWINSZ};
12 /// The struct required by the `TIOCGWINSZ` syscall; specified in the following
13 /// [man page](http://www.delorie.com/djgpp/doc/libc/libc_495.html).
16 /// Rows, in characters.
18 /// Columns, in characters.
20 /// Horizontal size, in pixels.
22 /// Vertical size, in pixels.
26 /// Returns the terminal screen size.
28 /// Returns `None` if the screen size is `(0, 0)` or is not able to be
30 pub fn size() -> Option<(Width, Height)> {
31 let is_tty = unsafe { isatty(STDOUT_FILENO) == 1 };
33 if !is_tty { return None; }
35 let (width, height) = unsafe {
36 let mut winsize = WinSize { ws_row: 0, ws_col: 0, ws_xpixel: 0, ws_ypixel: 0 };
37 ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut winsize);
39 (winsize.ws_col, winsize.ws_row)
42 Some((Width(width), Height(height)))
45 /// Returns the terminal screen width.
47 /// Returns `None` if the terminal width is detected as being <= 0 columns or is
48 /// not able to be determined at all.
49 pub fn width() -> Option<Width> {
52 if let Some((Width(width), Height(_))) = size {
59 /// Returns the terminal height.
61 /// Returns `None` if the terminal height is detected as being <= 0 rows or is
62 /// not able to be determined at all.
63 pub fn height() -> Option<Height> {
66 if let Some((Width(_), Height(height))) = size {
76 use super::super::{Width, Height};
78 use std::process::{Command, Stdio};
80 #[cfg(target_os = "linux")]
81 fn create_command() -> Command {
82 let mut cmd = Command::new("stty");
84 cmd.arg("/dev/stderr");
86 cmd.stderr(Stdio::inherit());
90 #[cfg(any(target_os = "freebsd", target_os = "macos"))]
91 fn create_command() -> Command {
92 let mut cmd = Command::new("stty");
94 cmd.arg("/dev/stderr");
96 cmd.stderr(Stdio::inherit());
102 let output = create_command().output().unwrap();
103 let stdout = String::from_utf8(output.stdout).unwrap();
104 assert!(output.status.success());
106 let cols = u16::from_str_radix(stdout.split_whitespace().last().unwrap(), 10).unwrap();
108 if let Some((Width(width), Height(_))) = size() {
109 assert_eq!(width, cols);
114 fn correct_height() {
115 let output = create_command().output().unwrap();
116 let stdout = String::from_utf8(output.stdout).unwrap();
117 assert!(output.status.success());
119 let rows = u16::from_str_radix(stdout.split_whitespace().next().unwrap(), 10).unwrap();
121 if let Some((Width(_), Height(height))) = size() {
122 assert_eq!(height, rows);