I'm writing a program that shows some information on screen and I want them to be updated each second.
What should I do?
I'm writing a C console application on Windows.
The Pianist, you can work with a console using WinAPI functions.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hConsole)
return;
After that determine the cursor position:
CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
GetConsoleScreenBufferInfo(hConsole, &csbi);
COORD coordCur = csbi.dwCursorPosition;
And...
while (TRUE) { // your cycle goes here
// ...
// now you can change position of the cursor
coordCur.X = newX;
coordCur.Y = newY;
SetConsoleCursorPosition(hConsole, coordCur);
// and print any information from the new position
printf("..."); // old text will be replaced
}
So you don't need to clear and refresh all console if you want to change a small piece of text.
ps. Don't forget to release a handle:
CloseHandle(hConsole);
There's a KB article on that topic.
Two options:
Write a function that will programmatically clear the screen
/* Standard error macro for reporting API errors */
#define PERR(bSuccess, api){if(!(bSuccess)) printf("%s:Error %d from %s \
on line %d\n", __FILE__, GetLastError(), api, __LINE__);}
void cls( HANDLE hConsole )
{
COORD coordScreen = { 0, 0 }; /* here's where we'll home the
cursor */
BOOL bSuccess;
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
DWORD dwConSize; /* number of character cells in
the current buffer */
/* get the number of character cells in the current buffer */
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
PERR( bSuccess, "GetConsoleScreenBufferInfo" );
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
/* fill the entire screen with blanks */
bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
dwConSize, coordScreen, &cCharsWritten );
PERR( bSuccess, "FillConsoleOutputCharacter" );
/* get the current text attribute */
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
PERR( bSuccess, "ConsoleScreenBufferInfo" );
/* now set the buffer's attributes accordingly */
bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
dwConSize, coordScreen, &cCharsWritten );
PERR( bSuccess, "FillConsoleOutputAttribute" );
/* put the cursor at (0, 0) */
bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
PERR( bSuccess, "SetConsoleCursorPosition" );
return;
}
Use a system function (not very pretty; requires starting a shell and a command)
system("cls");
Since you are on Windows, you can do this:
system('cls')
Here is an example:
#include <stdio.h>
int main()
{
printf("Press enter to clear the screen.");
getchar();
system("cls");
return 0;
}
If you are developing using Microsoft Visual Studoo and you want to programmatically clear the screen by outputting spaces, see Example 2 at http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx.
If you had searched google before asking, you would have found this link right in the first results.
To quote one of the methods:
Windows:
#include <windows.h>
void ClearScreen()
{
HANDLE hStdOut;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD count;
DWORD cellCount;
COORD homeCoords = { 0, 0 };
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == INVALID_HANDLE_VALUE) return;
/* Get the number of cells in the current buffer */
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
cellCount = csbi.dwSize.X *csbi.dwSize.Y;
/* Fill the entire buffer with spaces */
if (!FillConsoleOutputCharacter(
hStdOut,
(TCHAR) ' ',
cellCount,
homeCoords,
&count
)) return;
/* Fill the entire buffer with the current colors and attributes */
if (!FillConsoleOutputAttribute(
hStdOut,
csbi.wAttributes,
cellCount,
homeCoords,
&count
)) return;
/* Move the cursor home */
SetConsoleCursorPosition( hStdOut, homeCoords );
}
Related
I'm using Win32 API. This is just a very simple rendering of a rectangle. There are two screen buffers which I just swap alternately to display every next frame. Every time I run the program, I see horizontal flickers. I haven't tried this on any other device so I'm not really sure if you will be able see it too but if you do then perhaps you can show me some ways to get rid of it.
#include <stdio.h>
#include <string.h>
#include <windows.h>
HANDLE create_screen_buffer(SHORT height, SHORT width);
int main(void)
{
enum { SCREENS = 2 }; /* number of screen buffers */
HANDLE screen[SCREENS]; /* console screen buffers */
HANDLE next_screen;
int screen_index = 0;;
COORD screen_origin = { 0, 0 }; /* top-left corner of screen */
DWORD chars_written; /* used in `WriteConsole()` */
int i, j, row; /* loop counters */
enum { MAP_HEIGHT = 30, MAP_WIDTH = 70 };
/* this is where you prepare stuff before rendering to the screen */
char map[MAP_HEIGHT][MAP_WIDTH];
/* initialize screen buffers */
for (i = 0; i < SCREENS; ++i)
{
screen[i] = create_screen_buffer(MAP_HEIGHT, MAP_WIDTH);
if (screen[i] == NULL)
{
printf("ERROR: Failed to load screen buffers.\n");
/* free any previously loaded screen buffers */
for (j = 0; j < i; ++j)
CloseHandle(screen[j]);
}
}
/* initialize map */
for (i = 0; i < MAP_HEIGHT; ++i)
memset(map[i], '*', MAP_WIDTH);
for (i = 0; i < 200; ++i)
{
next_screen = screen[screen_index];
/* start writing from the top-left corner */
SetConsoleCursorPosition(next_screen, screen_origin);
/* write the map to the next frame */
for (row = 0; row < MAP_HEIGHT; ++row)
{
WriteConsoleA(next_screen, map[row], MAP_WIDTH, &chars_written, NULL);
WriteConsoleA(next_screen, "\n", 1, &chars_written, NULL);
}
/* display the next frame */
SetConsoleActiveScreenBuffer(next_screen);
/* set the next screen */
screen_index ^= 1;
/* just a little delay for more steady framerate */
Sleep(1);
}
/* free all screen buffers */
for (i = 0; i < SCREENS; ++i)
CloseHandle(screen[i]);
/* (optional) show the standard output */
SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
return 0;
}
HANDLE create_screen_buffer(SHORT height, SHORT width)
{
HANDLE screen;
COORD size;
CONSOLE_CURSOR_INFO cci;
screen = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, /* read/write access */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* shared */
NULL, /* default security attributes */
CONSOLE_TEXTMODE_BUFFER, /* must be TEXTMODE */
NULL /* reserved, must be NULL */
);
if (screen == NULL)
return NULL;
size.X = width + 1;
size.Y = height + 1;
SetConsoleScreenBufferSize(screen, size);
/* hide the text cursor */
GetConsoleCursorInfo(screen, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(screen, &cci);
return screen;
}
How does one create a native X11 window that works in EGL? Going through the eglIntro there is little documentation on the matter. Alternatively, is there a way to create native windows through EGL itself? There is an EGLNativeWindowType that I assume can be used instead of whatever X11's native window types are.
No, EGL itself does not provide an Xlib wrapper. You have to create the window by yourself.
Here is a minimal sample to get you started. It refers to GLES2, but it should work with GLES1 also.
First, you declare the Xlib objects(display and window).
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
// Native handles for window and display
Window win;
Display* xdisplay;
// EGL-related objects
EGLDisplay egl_display;
EGLConfig egl_conf;
EGLContext egl_context;
EGLSurface egl_surface;
int init_egl()
{
EGLint attr[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
// EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, /* If one needs GLES2 */
EGL_NONE
};
EGLint num_config;
EGLint major, minor;
EGLint ctxattr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
egl_display = eglGetDisplay( (EGLNativeDisplayType) xdisplay );
if ( egl_display == EGL_NO_DISPLAY ) {
printf("Error getting EGL display\n");
return 0;
}
if ( !eglInitialize( egl_display, &major, &minor ) ) {
printf("Error initializing EGL\n");
return 0;
}
printf("EGL major: %d, minor %d\n", major, minor);
/* create EGL rendering context */
if ( !eglChooseConfig( shell->egl_display, attr, &shell->egl_conf, 1, &num_config ) ) {
printf("Failed to choose config (eglError: %x)\n", eglGetError());
return 0;
}
if ( num_config != 1 ) {
return 0;
}
egl_surface = eglCreateWindowSurface ( egl_display, egl_conf, win, NULL );
if (egl_surface == EGL_NO_SURFACE ) {
printf("CreateWindowSurface, EGL eglError: %d\n", eglGetError() );
return 0;
}
egl_context = eglCreateContext ( egl_display, egl_conf, EGL_NO_CONTEXT, ctxattr );
if ( egl_context == EGL_NO_CONTEXT ) {
printf("CreateContext, EGL eglError: %d\n", eglGetError() );
return 0;
}
return 1;
}
From the main function you will call the X event handler procedure. I have left commented printf calls to show how the event values are named, so there's no need to lookup the documentation. If the concept of "Event loop" is not clear, then I recommend reading about general UI event processing.
void process_xevent(XEvent xev) {
// XNextEvent( xdisplay, &xev );
switch (xev.type)
{
case MotionNotify:
// printf("motion: %d %d\n", xev.xbutton.x, xev.xbutton.y);
break;
case KeyRelease:
// printf("rel (%d)\n", XLookupKeysym (&xev.xkey, 0));
break;
case KeyPress:
// printf("keypress (%d)\n", XLookupKeysym (&xev.xkey, 0));
break;
case ButtonPress:
// printf("BPress: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y);
// printf("Type=%d\n", (int)xev.xbutton.type);
break;
case ButtonRelease:
// printf("BRelease: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y);
// printf("Type=%d\n", (int)xev.xbutton.type);
break;
}
}
Finally, in the main() routine you create and open display/Xwindow.
int main()
{
int egl_error;
Window root;
XSetWindowAttributes swa;
/* open standard display (primary screen) */
xdisplay = XOpenDisplay ( NULL );
if ( xdisplay == NULL ) {
printf("Error opening X display\n");
return 0;
}
The window is created and shown once you have the Display opened.
Finally, in the main() routine you create and open display/Xwindow.
// get the root window (usually the whole screen)
root = DefaultRootWindow( shell->xdisplay );
// list all events this window accepts
swa.event_mask =
StructureNotifyMask |
ExposureMask |
PointerMotionMask |
KeyPressMask |
KeyReleaseMask |
ButtonPressMask |
ButtonReleaseMask;
// Xlib's window creation
win = XCreateWindow (
xdisplay, root, 0, 0, 640, 480, 0,
CopyFromParent, InputOutput, CopyFromParent, CWEventMask,
&swa );
XMapWindow ( xdisplay , win ); // make window visible
XStoreName ( xdisplay , win , "EGL" );
When you have the window, intialise the EGL.
egl_error = init_egl();
if (!egl_error) {
return 1;
}
Once you have the EGL & Xlib objects, you can start the event processing loop.
while (1) {
int keycode;
XEvent xev;
if ( XPending ( xdisplay ) )
if (XCheckWindowEvent(shell->xdisplay, shell->win, global_event_mask, &xev))
process_xevent(shell, xev);
/* if (should_exit) { break; } // set some global flag if you want to exit */
eglMakeCurrent( egl_display, egl_surface, egl_surface, egl_context );
/* Call OpenGL as you see fit */
/* get rendered buffer to the screen */
eglSwapBuffers ( egl_display, egl_surface );
}
// deinitialize
}
This should get you started. The code is extracted from a larger project, so there might have be typos introduced while removing irrelevant things.
To conclude the answer and to be more precise, here EGLNativeWindowType is specialized to Window from X11/Xlib.h header and EGLNativeDisplayType is Display*.
An easier way might be to use libxcb, but I do not have any tested sample code. The GLFW library can be a useful source of OS-dependant OpenGL context creation routines.
My laptop is Macbook Pro.
I installed libxcb on it and tried a simple example that x.org given:
#include <unistd.h> /* pause() */
#include <xcb/xcb.h>
int main ()
{
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
/* Ask for our window's Id */
win = xcb_generate_id(c);
/* Create the window */
xcb_create_window (c, /* Connection */
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
win, /* window Id */
screen->root, /* parent window */
0, 0, /* x, y */
150, 150, /* width, height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
0, NULL); /* masks, not used yet */
/* Map the window on the screen */
xcb_map_window (c, win);
/* Make sure commands are sent before we pause, so window is shown */
xcb_flush (c);
pause (); /* hold client until Ctrl-C */
return 0;
}
But there is no window shown on screen. Is there something I forget?
My GTK+2/C application uses Opencv library to grab frames continuously from the web camera feed and there's a UI button, which should calculate some information by grabbing a frames upon clicking.
This button click calculation takes 1-2 seconds and depend on the system resources. (on Raspberry pi, it takes 3-5 seconds)
Previously all functionalities (viewing + calculations) were inside the same main process. However when doing the calculation, whole app (video feed) used to freeze until the completion if the calculation.
I have implemented fork()to make child processes and keep the interprocess communications via pipe() to update the UI with calculated data.
However now the lagging time got lot bigger like 5-6 seconds.
below shows the sample code.
Is there any particular way to avoid this kind of lagging of the main process?
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <diamond_calcs.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/videodev.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include "highgui.h"
#include <X11/Xlib.h>
/* declaring the opencv capture variable */
CvCapture* capture, *fm_capture;
GdkPixbuf* pix;
IplImage* frame, *frame_sized;
gboolean expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data);
gboolean timeout(gpointer data);
gboolean autoon_clicked_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data[]);
// This function grabs a frame and recording some values. also this is the function called by the child process also.
gboolean frame_grabber(void)
{
/* setting up the edge ditection */
IplImage *frame_bgr;
if(frame){
//frame_bgr = cvQueryFrame( capture );
frame_bgr = frame_sized;
}
else{
frame_bgr = cvLoadImage("./data/media/novideo.png", 1);
}
/* Converting Color SPACE to greyscale */
int y_pos, x_pos;
int counter=0;
typedef enum { false, true } bool;
bool col_break = false;
for(int y=0;y<frame_bgr->height;y++)
{
for(int x=0;x<frame_bgr->width;x++)
{
CvScalar color = cvGet2D(frame_bgr, y, x);
if(color.val[0]<color_filter_thres){
if (y_pos == y){
counter++;
}
x_pos = x;
y_pos = y;
if (counter > 2){
//printf("top: %i, %i \n", x_pos, y_pos);
col_break = true;
break;
}
}
}
if (col_break){
break;
}
}
ruler_top_cal_preset = y_pos;
/* bottom ruler - scanning backwards*/
int y_pos_bot, x_pos_bot;
int counter_bot=0;
bool col_break2 = false;
for(int y_b=frame_bgr->height-1;y_b>0;y_b--)
{
for(int x_b=frame_bgr->width-1;x_b>0;x_b--)
{
CvScalar color_bot = cvGet2D(frame_bgr, y_b, x_b);
if(color_bot.val[0]<color_filter_thres){
if (y_pos_bot == y_b){
counter_bot++;
}
x_pos_bot = x_b;
y_pos_bot = y_b;
if (counter_bot > 2){
//printf("bottom: %i, %i \n", x_pos_bot, y_pos_bot);
col_break2 = true;
break;
}
}
}
if (col_break2){
break;
}
}
ruler_bottom_cal_preset = y_pos_bot;
dfactor_preset = ruler_bottom_cal_preset - ruler_top_cal_preset;
}
/*
* main
*
* Program begins here
*/
//####### Lot of processes going inside main, ignore it, just focus on the program flow
int main( int argc, char **argv )
{
/* variables structs to load the gtk_ based widgets and windows */
GtkBuilder *builder;
GtkWidget *window, *event_box, *drawing_area;
GError *error = NULL;
GError *error_settings = NULL;
GtkButton *button;
GtkLabel *label;
/* Init GTK+ */
gtk_init( &argc, &argv );
/* Create new GtkBuilder object */
builder = gtk_builder_new();
/* Load UI from file. If error occurs, report it and quit application. */
if( ! gtk_builder_add_from_file( builder, "file_glade.glade", &error ) )
{
g_warning( "%s", error->message );
g_free( error );
return( 1 );
}
/* Get main window pointer from UI */
window = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );
/* creating the drawing area */
drawing_area = gtk_drawing_area_new();
gtk_container_add (GTK_CONTAINER(event_box), drawing_area);
gtk_widget_show (drawing_area);
/* connects the draw (expose-event) with the handler */
g_signal_connect (drawing_area, "expose-event",
G_CALLBACK (expose_event_callback), NULL);
gtk_label_set(labels[0], "Min :");
//####### Here goes the calculation clicking
gtk_signal_connect (GTK_OBJECT (gtk_builder_get_object( builder, "autoon_button" )), "clicked",
GTK_SIGNAL_FUNC (autoon_clicked_cb), labels);
/* Show window. All other widgets are automatically shown by GtkBuilder */
gtk_widget_show( window );
/* load last saved values */
file_load( spinners );
//#######
int fd;
if((fd = open("/dev/video0", O_RDONLY)) == -1){
printf("NO CAP\n");
capture = NULL;
}
else{
capture = cvCreateCameraCapture(0);
cvSetCaptureProperty(capture, CV_CAP_PROP_BRIGHTNESS, brght);
cvSetCaptureProperty(capture, CV_CAP_PROP_CONTRAST,contra);
cvSetCaptureProperty(capture, CV_CAP_PROP_SATURATION, satu);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 800);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 600);
// ## remove the forking from here and add that to the expose function
pid_t pID1 = vfork();
if (pID1 == 0) // child process
{
g_timeout_add (15, timeout, drawing_area);
//_exit(0);
}
else if ( pID1 < 0 ){
printf("Failed to fork video overlay child process \n");
exit(1);
}
}
/* Destroy builder, since we don't need it anymore */
g_object_unref( G_OBJECT( builder ) );
//g_object_unref( G_OBJECT( settings_builder ) );
//g_object_unref( G_OBJECT( about_builder ) );
/* Start main loop */
gtk_main();
return( 0 );
}
/* This function runs every x seconds and making the video feed */
/*
* Function: expose_event_callback
* --------------------
* When the widget is exposed of force to expose ths function handler will run to generate the video feed
*
* returns: none
*/
gboolean
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
/* Capture a single frame from the video stream */
if (capture){
frame = cvQueryFrame( capture );
frame_sized = frame;
pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData,
GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width,
frame->height, (frame->widthStep), NULL, NULL);
}
else{
printf("You've done it\n");
pix = gdk_pixbuf_new_from_file("./data/media/novideo.png", NULL);
}
/* putting the generated pix buff to the correct layout (GTK widget) */
gdk_draw_pixbuf(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0,
-1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are GDK_RGB_DITHER_MAX, GDK_RGB_DITHER_NORMAL */
return TRUE;
}
/*
* Function: timeout
* --------------------
* This function runs inbetween given time period. It calls the required functions to generate video and drawing
*
* returns: none
*/
gboolean timeout(gpointer data)
{
/* DEBUG print */
//printf("Time out Hello: %d\n", rand());
/* Redraws the Widget. Widget will call for the callback function again */
gtk_widget_queue_draw (data);
/* Starting the drawing function */
//ofdra(data,NULL);
return TRUE;
}
gboolean autoon_clicked_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data[])
{
char display1_entry_text[100];
int x = 1;
int pfds[2];
pipe(pfds);
pid_t pID = fork();
if (pID == 0) // child process
{
double ytops[10];
double ybots[10];
double min_diam;
double max_diam;
double avg_diam;
clock_t t1, t2,end_t; // clocking for debugging purposes
t2 = clock();
for(int i=0;i<15;i++)
{
//measure_clicked_callback(widget, NULL, data);
frame_grabber();
ytops[i] = ruler_top_cal_preset;
ybots[i] = ruler_bottom_cal_preset;
t1 = clock();
float x = (float)(t1-t2);
float y = x/CLOCKS_PER_SEC;
float z = y*1000;
t2 = t1;
}
/* sorting arrays for ascending order */
if(ybots && ytops){
array_sorter(ybots);
array_sorter(ytops);
min_diam = (ybots[0]-ytops[9])/scale_factor;
max_diam = (ybots[9]-ytops[0])/scale_factor;
avg_diam = (min_diam+max_diam)/2;
}
sprintf(display1_entry_text0,"Min : %.3g",min_diam);
write(pfds[1], display1_entry_text0, 100);
_exit(0);
}
else if(pID <0){
printf("Failed to fork \n");
exit(1);
}
else{
//parent process
char buf[100];
read(fpds[0], buf, 100);
//updates the gtk interface with read value
gtk_lable_set(data[0], buf);
wait(NULL);
}
return TRUE;
}
**Note I have pasted this code from the actual whole code, also this will not run. Pasted only here for give some idea about what I'm trying to achieve.
It looks like you have blocking read and wait calls in your parent process. In other words, despite the fact that you spawn a child process to perform the calculations, you still block your parent process till the child process completes. No parallelism is achieved.
I would suggest having a worker thread in the process that would do the calculations and notify the main thread when the results are available.
In the parent process/thread you should make the read end of the pipe non-blocking and register it with the event loop. Once the read end becomes ready for read, read all data in non-blocking mode.
Set a signal handler for SIGCHLD and call wait in it to release the child process resources.
I am embedding my command line application into a ncurses-TUI.
My application (client/server) should be able to print a lot lines if needed, but it must stays into the windows I defined :
/* Removed code */
ITEM **my_items;
int c;
MENU *my_menu;
WINDOW *my_menu_win;
int n_choices, i;
// Initialize curses
initscr(); // initializes the screen
start_color();
cbreak();
noecho();
keypad(stdscr, TRUE);
init_pair(1, COLOR_RED, COLOR_BLACK);
/* Removed code */
/* Create items */
n_choices = ARRAY_SIZE(choices);
my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
for(i = 0; i < n_choices; ++i)
{
my_items[i] = new_item(choices[i], choices[i]);
}
/* Removed code */
/* Create menu */
my_menu = new_menu((ITEM **)my_items);
/* Set menu option not to show the description */
menu_opts_off(my_menu, O_SHOWDESC);
/* Create the window to be associated with the menu */
my_menu_win = newwin(WIN_HEIGHT, WIN_WIDTH, WIN_YPOS, WIN_XPOS);
keypad(my_menu_win, TRUE);
/* Set main window and sub window */
set_menu_win(my_menu, my_menu_win);
set_menu_sub(my_menu, derwin(my_menu_win, WIN_HEIGHT/2, WIN_WIDTH/2, WIN_HEIGHT/2-3, WIN_WIDTH/2-10));
/* Set menu mark to the string " * " */
set_menu_mark(my_menu, ">");
/* Print a border around the main window and print a title */
box(my_menu_win, 0, 0);
/* Removed code */
/* Post the menu */
post_menu(my_menu);
wrefresh(my_menu_win);
endwin(); //resets the screen
}
1 How can I add a windows inside this windows with a scrolling content where all the output that usually goes to the terminal would be print
2 ...or is it possible to link that windows with the terminal output ?