33

This is two questions really:

  • how do I resize a curses window, and
  • how do I deal with a terminal resize in curses?

Is it possible to know when a window has changed size?

I really can't find any good doc, not even covered on http://docs.python.org/library/curses.html

Pez Cuckow
  • 14,048
  • 16
  • 80
  • 130

5 Answers5

36

Terminal resize event will result in the curses.KEY_RESIZE key code. Therefore you can handle terminal resize as part of a standard main loop in a curses program, waiting for input with getch.

Michael McLoughlin
  • 1,062
  • 1
  • 11
  • 14
  • 2
    This is right, but only when ncurses is compiled with --enable-sigwinch. In particular, the libncurses in Debian and Ubuntu doesn't have that turned on; I'm not sure why. – the paul Jul 20 '13 at 05:05
  • @thepaul: at least in my Ubuntu 12.04 I do get `curses.KEY_RESIZE` code when I resize the terminal emulator window. – MestreLion Feb 10 '15 at 03:10
  • Good, I'm glad they fixed that. – the paul Feb 11 '15 at 17:26
10

I got my python program to re-size the terminal by doing a couple of things.

# Initialize the screen
import curses

screen = curses.initscr()

# Check if screen was re-sized (True or False)
resize = curses.is_term_resized(y, x)

# Action in loop if resize is True:
if resize is True:
    y, x = screen.getmaxyx()
    screen.clear()
    curses.resizeterm(y, x)
    screen.refresh()

As I'm writing my program I can see the usefulness of putting my screen into it's own class with all of these functions defined so all I have to do is call Screen.resize() and it would take care of the rest.

prairiedogg
  • 6,323
  • 8
  • 44
  • 52
jarsever
  • 690
  • 1
  • 7
  • 15
  • Could you add whatever is needed to make this code self-contained? For example I'm not sure what "screen" is. – Don Hatch Oct 23 '15 at 06:28
  • 1
    @DonHatch Hopefully that is what you are looking for. Here is a good little tutorial also if you are wanting it. https://docs.python.org/3/howto/curses.html – jarsever Oct 23 '15 at 15:20
  • He meant that your code doesn't work if you just copy and past to test it as there are many things missing. – answerSeeker Jul 29 '17 at 04:00
  • 3
    where do you take `y, x` in `resize = curses.is_term_resized(y, x)` ? is it old sizes? If so, how do you get the terminal size? for me, `screen.getmaxyx()` doesn't seem to return the updated size. When I change the size of command line, it is still the same... – Brambor Nov 29 '19 at 03:22
5

I use the code from here.

In my curses-script I don't use getch(), so I can't react to KEY_RESIZE.

Therefore the script reacts to SIGWINCH and within the handler re-inits the curses library. That means of course, you'll have to redraw everything, but I could not find a better solution.

Some example code:

from curses import initscr, endwin
from signal import signal, SIGWINCH
from time import sleep

stdscr = initscr()

def redraw_stdscreen():
    rows, cols = stdscr.getmaxyx()
    stdscr.clear()
    stdscr.border()
    stdscr.hline(2, 1, '_', cols-2)
    stdscr.refresh()

def resize_handler(signum, frame):
    endwin()  # This could lead to crashes according to below comment
    stdscr.refresh()
    redraw_stdscreen()

signal(SIGWINCH, resize_handler)

initscr()

try:
    redraw_stdscreen()

    while 1:
        # print stuff with curses
        sleep(1)
except (KeyboardInterrupt, SystemExit):
    pass
except Exception as e:
    pass

endwin()
JackLeEmmerdeur
  • 724
  • 11
  • 17
  • Calling endwin/initscr in a signal handler is a good way to get core dumps. – Thomas Dickey Jul 26 '19 at 08:07
  • @ThomasDickey Thanks for the info. I've removed one initscr() from the signal-handler, what presumably doesn't improve it much. The c-code in an [accepted answer](https://stackoverflow.com/a/13707598/3469861), recommends to use `endwin()` followed by `refresh()`. Am I right, that python3 would inform about the user about the coredump? If yes, I hadn't have one up to now, while furiously resizing my terminal. – JackLeEmmerdeur Jul 30 '19 at 11:03
1

This worked for me when using curses.wrapper():

if stdscr.getch() == curses.KEY_RESIZE:
    curses.resizeterm(*stdscr.getmaxyx())
    stdscr.clear()
    stdscr.refresh()
Mike Conigliaro
  • 1,144
  • 1
  • 13
  • 28
  • 1
    I tried this using terminal inside **VS Code** and was stuck in the loop most probably because of infinitely repeating `curses.KEY_RESIZE` events. A call to `curses.flushinp()` didn't help. A pity... this answer helped me the best, nevertheless. – qdbp Dec 07 '20 at 11:14
  • @qdbp infinitely repeating `curses.KEY_RESIZE` events? If you can't depend on `stdscr.getch()`, I guess you'll just have to keep track of when `stdscr.getmaxyx()` returns new values. – Mike Conigliaro Dec 08 '20 at 17:47
-2

It isn't right. It's an ncurses-only extension. The question asked about curses. To do this in a standards-conforming way you need to trap SIGWINCH yourself and arrange for the screen to be redrawn.

embert
  • 7,336
  • 10
  • 49
  • 78