Window Resizing (Curses)

I just started learning curses by following this tutorial

http://viget.com/extend/game-programming-in-c-with-the-ncurses-library

After changing #include <ncurses.h> to #include <curses.h> everything worked fine except for the handling window resizing part. I did the same thing (putting getmaxyx into the main loop), but my program doesn't work as it supposed to. The 'o' keeps bouncing off on the same location. I tried to debug and saw the values of max_y and max_x don't change after resizing the console window.

The code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <curses.h>
#include <unistd.h>

#define DELAY 30000

int main()
{
    int x = 0, y = 0;
    int max_y = 0, max_x = 0;
    int next_x = 0;             // Check next position
    int direction = 1;

    initscr();
    noecho();
    curs_set(FALSE);

    while(1)
    {
        // Global var 'stdscr' is created by the call to 'initscr()'
        getmaxyx(stdscr, max_y, max_x);

        clear();                // Clear the screen
        mvprintw(y, x, "o");    // Print ball at x, y
        refresh();

        usleep(DELAY);          // Shorter delay between movements
        next_x = x + direction;

        if(next_x >= max_x || next_x < 0)
            direction *= -1;
        else
        {
            x += direction;
        }

    }
    endwin();

    return 0;
}


Anyone has any idea what did I do wrong?

I'm doing this in CodeBlocks on a Windows 7 machine.
Last edited on
Your program works fine for me on Linux (using ncurses).
That's weird. Maybe it's the fact that I'm doing it on Windows?
Peter87's NCurses is properly configured to handle SIGWINCH -- not all *nixen are.

Either way, you need to tell curses to update. And, unfortunately, this is something where NCurses and PDCurses work differently.

Give me a little and I'll post something that handles things properly cross-platform.
Okay, sorry, here's what I've learned.

Apparently (and I did not realize this), PDCurses does not handle window resize events on Win32.

Resizing the console window is such a pain on Windows anyway...


Have you tried messing with Project Pluto's win32a PDCurses?
http://www.projectpluto.com/win32a.htm

I haven't messed with it (yet), but it looks nice!
(And it handles window resizing nicely!)
Alright, win32a Curses is pretty cool. Here's what I did:

I've got PDCurses installed on my Windows with two versions:
- libpdcurses.a -- the standard console version
- libpdcurses.win32a.a -- the Project Pluto version

And on Fedora I've got NCurses installed the usual way.

a.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <cstdlib>
#include <curses.h>

//----------------------------------------------------------------------------
struct curses
{
  curses()
  {
    // Win32a PDCurses -- make window resizable
    ttytype[0] = 25;                  // min  25 lines
    ttytype[1] = (unsigned char)255;  // max 255 lines
    ttytype[2] = 80;                  // min  80 columns
    ttytype[3] = (unsigned char)255;  // max 255 columns
    
    initscr();
    noecho();
    nonl();
    raw();
    keypad( stdscr, TRUE );  // (required for resizing to work on Win32a ???)
    curs_set( 0 );

    #ifndef _WIN32
    // Make the ESC key take only a little time,
    // unless the user has set a specific ESCDELAY in their environment.
    const char* escdelay = std::getenv( "ESCDELAY" );
    if (escdelay) ESCDELAY = std::atoi( escdelay );
    else          ESCDELAY = 250;
    #endif
  }
  
 ~curses()
  {
    endwin();
  }
};

curses _;

//----------------------------------------------------------------------------
void resize_event()
{
  int w, h;
  resize_term( 0, 0 );
  getmaxyx( stdscr, h, w );
  mvprintw( 10, 10, "Window size = %d, %d      ", w, h );
  refresh();
}

//----------------------------------------------------------------------------
int main()
{
  printw( "Resize your window!\n\rPress either ENTER or ESC to quit." );
  resize_event();
  
  bool done = false;
  while (!done)
  {
    int ch = getch();
    switch (ch)
    {
      case KEY_RESIZE: 
        resize_event(); 
        break;
      
      case '\033':
      case '\n':
      case '\r':
        done = true; 
        break;
    }
  }
  
  mvprintw( 10, 10, "Press the 'any' key                  " );
  refresh();
  getch();
}

Makefile
1
2
3
4
5
6
7
8
9
10
11
all:
	echo You must specify one of 'pdcurses', 'win32a', or 'ncurses'

pdcurses: a.cpp
	g++ -Wall -std=c++11 -pedantic -s a.cpp -lpdcurses

win32a: a.cpp
	g++ -Wall -std=c++11 -pedantic -s a.cpp -lpdcurses.win32a -lgdi32 -lcomdlg32 -mwindows

ncurses: a.cpp
	g++ -Wall -std=c++11 -pedantic -s a.cpp -lncurses

The standard version on Windows doesn't do anything useful, alas.

The win32a version on Windows works swimmingly.
The *nix version on Fedora works swimmingly.

Hope this helps.

[edit] Fixed makefile for win32a
Last edited on
How exactly am I supposed to use Project Pluto's win32a PDCurses?

I get 46 undefined reference errors when I link to the pdcurses.a in win32a folder. Linking to the pdcurses.a in win32 folder gives no error, but I got the same result as my first attempt ('o' keeps bouncing off on the same spot even after resizing console window).
You need to install it first.
http://www.projectpluto.com/win32a.htm

Sigh. A quick tutorial. Using C::B to run a makefile is not fun, so I recommend you compile from the command prompt directly. Here's how.

Download and setup  
Get http://www.projectpluto.com/win32a.zip

Save it somewhere useful. I saved mine at C:\Users\Michael\Programming\Curses.
In Windows Explorer, right-click the file and select "Extract all..." from the popup menu.
Double click on the new directory.
Open a command prompt there. (Press Alt-D to highlight the address bar and type cmd.exe.)

Type g++ --version to verify that MinGW will work. If it does not, you need to add it to the path:

    For most standard MinGW installations, type path C:\MinGW\bin;%PATH%  
    For TDM-GCC-w64, type path C:\TDM-GCC-64\bin;%PATH%  
    (If your MinGW is somewhere else, substitute the correct path.)

Compiling  
Now type the following commands.

1
2
cd win32a
mingw32-make -f mingwin32.mak WIDE=Y UTF8=Y

That was easy!

Installing
We're going to put the new "pdcurses.a" and "panel.a" library files where they belong in the MinGW subdirectory. We're also going to put the public header files where they belong in MinGW.

As in my post above, I wanted the standard PDCurses and Pluto's to be both available, so I renamed the "pdcurses.a" to "libpdcurses.win32a.a" and the "panel.a" to "libpanel.win32.a". You can do the same, but the following assumes you wish to simply use the win32a curses only and overwrite any extant libpdcurses.a and libpanel.a files.

Standard MinGW:
1
2
3
4
5
copy ..\curses.h C:\MinGW\include
copy ..\panel.h  C:\MinGW\include
copy ..\term.h   C:\MinGW\include
copy pdcurses.a  C:\MinGW\mingw32\lib\libpdcurses.a
copy panel.a     C:\MinGW\mingw32\lib\libpanel.a

TDM-GCC-w64:
1
2
3
4
5
copy ..\curses.h C:\TDM-GCC-64\x86_64-w64-mingw32\include\
copy ..\panel.h  C:\TDM-GCC-64\x86_64-w64-mingw32\include\
copy ..\term.h   C:\TDM-GCC-64\x86_64-w64-mingw32\include\
copy pdcurses.a  C:\TDM-GCC-64\x86_64-w64-mingw32\lib\libpdcurses.a
copy panel.a     C:\TDM-GCC-64\x86_64-w64-mingw32\lib\libpanel.a


32-bit  
Some MinGW's are capable of both 32-bit and 64-bit compiles. Those MinGWs will produce a 64-bit library by default. In order to also get a 32-bit version we will have to compile one.

Open the mingwin32.mak file and insert two lines to modify CFLAGS and LDFLAGS:
44
45
46
47
48
49
50
51
52
53
54
55
ifeq ($(DEBUG),Y)
        CFLAGS  = -g -Wall -DPDCDEBUG
        LDFLAGS = -g
else
        CFLAGS  = -O4 -Wall
        LDFLAGS =
endif

CFLAGS  += -m32
LDFLAGS += -m32

CFLAGS += -I$(PDCURSES_SRCDIR)








<-- insert this line
<-- and this line

[edit] Don't forget to delete all the .o files first! [/edit]

Then recompile and copy the resulting library files as before, except to the lib32 directory:
1
2
copy pdcurses.a C:\TDM-GCC-64\x86_64-w64-mingw32\lib32\libpdcurses.a
copy panel.a    C:\TDM-GCC-64\x86_64-w64-mingw32\lib32\libpanel.a

Now your MinGW will properly compile with PDCurses when you specify the -m32 or -m64 flag.

Whew. All done!

Edited to make the DOS commands a little more readable...
Last edited on
Apparently I have to link libgdi32.a and libcomdlg32.a for it to compile, but for some reason I get two console windows. One is empty and another one with the 'o' moving back and forward. I can resize the empty one, but I can't do anything on the one with the 'o' (I assume this is because it's an infinite loop?).

I guess I'll play around with curses a bit more.

Thanks for the help everyone!

Ah, sorry, I forgot about that. You need to link with

-lpdcurses -lgdi32 -lcomdlg32

AND you need to specify a GUI application target with

-mwindows

You can do that last one in Code::Blocks by going to Code Blocks-->Properties-->Build Targets-->Type and making it read "GUI application" (instead of "Console application").
Topic archived. No new replies allowed.