Best way of finding terminal width/height?

Grant Edwards grante at visi.com
Sun Feb 5 21:10:35 EST 2006


On 2006-02-05, Joel Hedlund <joel.hedlund at gmail.com> wrote:

>> Which details?  We'd be happy to explain the code. Not that
>> you need to understand the details to use the code.
>
> OK, why '1234' in here, and what's termios.TIOCGWINSZ,

Second question first: TIOCGWINSZ is just a platform-defined
magic number that you pass to ioctl() to tell it that you want
to get the terminal window size:

  Terminal IO Control Get WINdow SiZe
  T        IO C       G   WIN    S Z  

> and how should I have known this was the way too do it?

Because if you're writing low level screen management stuff for
Unix you know that sort of stuff.  BTW: don't forget to attach
a handler to the window-size-change signal (SIGWINCH) so that
you know when your terminal changes sizes (which means you need
to call the function to get the current size again and
re-layout your screen).

> fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')

Now the '1234' question.  This bit _is_ a bit ugly. ioctl()
expects a third parameter which is input data in the case of
"write-like" ioctl() calls.  If the ioctl() is a "read-like"
call, the third argument is merely a string that specifies how
many data bytes the ioctl call is expected to return.  In this
case the TIOGWINSZ ioctl will return 4 bytes of data (two
16-bit integers), so we pass it a 4 byte string to tell the
ioctl module how much memory to allocate for the value to be
returned.

It's explained in more detail at 

http://docs.python.org/lib/module-fcntl.html

> Am I interpreting C structs here,

Yes.  Which I can see might be considered "un-pythonic", but
it's a common enough paradigm that the "struct" module is
included in the standard library for just that task.

> and if so - why is python giving me C structs?

Because ioctl() is Unix's junk-drawer.  It's full of
miscellaneous crap that didn't fit anywhere else (and often was
an after-thought).  The python module would require a _lot_ of
very nasty system-specific knowledge and logic to implicitly
figure out the types of passed and returned data. Since it's
not used that much, nobody has put the work required to make
Python's ioctl module omniscient.  Some of the more common
stuff probably has been provided in a more abstract manner.

> And what's 'hh' anyway? struct.unpack('hh', ... )

It's specifying the types of the "fields" within the struct.
'h' means a short (16-bit) integer.  The struct returned from
the ioctl() is going to contain two 16-bit integers. The full
description of struct formats is at

http://docs.python.org/lib/module-struct.html


> Why 0, 1 and 2?
> cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)

0 is the file descriptor for standard input, 1 is standard
output, and 2 is standard error.  If your program has a
terminal, one of them may be connected to it.

> > I don't know if it will work on MS Windows or not.
>
> Linux and unix are my main concerns, but it would be neat to know if it 
> would work on Win/Mac.

Homey don't do Windows, so you'll have to ask somebody else that.

> What OS:es set the COLS/ROWS env vars?

None.  Some shells set those environment variables.  They may
be wrong if the terminal has changed size since your program
was started.

> What OS:es can leverage the termios module?

I don't know what you mean by "leverage the termios module".

> I have a hunch that we have 100% overlap there,

No comprende.

> and then this solution leaves me at square one (arbitrary
> choice of 80*25) for the others OS:es (or am I wrong?).

Dunno.  I've been using Unix for 25+ years.  I tried Windows a
few times and though it sucked rather badly.  Now that Cygwin
is around it sucks slightly less (but only slightly).

> How do Win/Mac people do this?

AFAICT, Win/Mac people don't.  

They just don't write console programs.  Unless you're talking
about Mac OS X, and that's just BSD Unix, so they do it using
ioctl().

>> What's unpythonic about the example you found?
>
> Maybe I did bit of poor wording there, but In my experience python 
> generally has a high level of abstraction, which provides linguistically 
> appealing (as in "in english") solutions to almost any problem.

For popular and common tasks that's true.  For stuff nobody
ever does, you usually fall back to the underlying platform
mechanism.

> Like for example how os.path.isfile(s) tells me if my string s
> corresponds to a file. I guess that's what I mean really. I
> sort of expected to find something like my terminal_size()
> example in the built-in modules.

I would guess that the real answer is that so few people have
ever wanted it that nobody has ever created a module and
submitted it.  Feel free... ;)

> I didn't expect to have to do that struct fcntl ioctl boogey
> to solve this relatively simple (?) problem.

Getting terminal size may be a simple problem, but it's only a
small part of a complex and difficult task (managing 
"full-screen" terminal-mode apps).  People who write
terminal-mode apps in python generally do one of two things:

 1) Just write a normal Unix-like text processing "filter". 
    Those programs don't generally care about the terminal size
    since they may not be connected to a terminal at all.

 2) Use a terminal management library like ncurses+panel or
    slang+newt.  That way you get a much higher level more
    abstract API.
    
-- 
Grant Edwards                   grante             Yow!  Don't SANFORIZE me!!
                                  at               
                               visi.com            



More information about the Python-list mailing list