Fix madtty_color_pair for terms with only 8 colors.
[apps/madtty.git] / demo / boxshell.c
1 /* Just a simple example program that creates a terminal in a frame
2  * and lets the user interact with it.
3  *
4  * To compile:
5  *    gcc -o boxshell boxshell.c $(pkg-config madtty --cflags --libs)
6  */
7
8 #include <ncurses.h>
9
10 #include <fcntl.h>
11 #include <locale.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/time.h>
17 #include <termios.h>
18 #include <time.h>
19
20 #include <madtty/madtty.h>
21
22 static int getout = 0, sigwinch = 0;
23 static int screen_w, screen_h;
24 static WINDOW *term_win;
25 static struct timeval const slice = { 0, 1000 * 1000 / 100 };
26
27 void handler(int signo)
28 {
29     switch (signo) {
30       case SIGCHLD:
31         getout = 1;
32         break;
33       case SIGWINCH:
34         sigwinch = 1;
35         break;
36     }
37 }
38
39 static struct timeval timeval_add(struct timeval a, struct timeval b)
40 {
41     int usec = a.tv_usec + b.tv_usec;
42     a.tv_sec += b.tv_sec;
43     while (usec > 1000 * 1000) {
44         a.tv_sec += 1;
45         usec -= 1000 * 1000;
46     }
47     a.tv_usec = usec;
48     return a;
49 }
50
51 static int is_expired(struct timeval now, struct timeval expiry)
52 {
53     return now.tv_sec > expiry.tv_sec
54         || (now.tv_sec == expiry.tv_sec && now.tv_usec > expiry.tv_usec);
55 }
56
57 int main(void)
58 {
59     madtty_t *rt;
60     int dirty = 0, pty;
61     struct timeval next;
62
63     signal(SIGCHLD, handler);
64     signal(SIGWINCH, handler);
65
66     setlocale(LC_ALL, "");
67     initscr();
68     start_color();
69     noecho();
70     raw();
71     nodelay(stdscr, TRUE);
72     keypad(stdscr, TRUE);
73     curs_set(0);
74     ESCDELAY=50;
75     madtty_init_colors();
76     getmaxyx(stdscr, screen_h, screen_w);
77
78     /* create a window with a frame */
79     term_win = newwin(screen_h - 2, screen_w - 2, 1, 1);
80     rt = madtty_create(screen_h - 2, screen_w -2);
81     {
82         const char *path = getenv("SHELL") ?: "/bin/sh";
83         const char *args[] = { path, "--login", NULL};
84
85         madtty_forkpty(rt, path, args, &pty);
86     }
87
88     /* keep reading keypresses from the user and passing them to the terminal;
89      * also, redraw the terminal to the window at each iteration */
90     gettimeofday(&next, NULL);
91     while (!getout) {
92         struct timeval tv = { 0, 1000 * 1000 / 100 };
93         fd_set rfds;
94         int ch;
95
96         FD_ZERO(&rfds);
97         FD_SET(0, &rfds);
98         FD_SET(pty, &rfds);
99
100         if (select(pty + 1, &rfds, NULL, NULL, &tv) > 0) {
101             if (FD_ISSET(pty, &rfds)) {
102                 madtty_process(rt);
103                 dirty = 1;
104             }
105         }
106
107         if (sigwinch) {
108             int fd, cols = -1, rows = -1;
109             struct winsize w;
110
111             if ((fd = open("/dev/tty", O_RDONLY)) != -1) {
112                 if (ioctl(fd, TIOCGWINSZ, &w) != -1) {
113                     rows = w.ws_row;
114                     cols = w.ws_col;
115                 }
116                 close(fd);
117             }
118             if (rows <= 0) {
119                 rows = atoi(getenv("LINES") ?: "24");
120             }
121             if (cols <= 0) {
122                 cols = atoi(getenv("COLUMNS") ?: "80");
123             }
124
125             resizeterm(rows, cols);
126             madtty_resize(rt, rows - 2, cols - 2);
127             wresize(term_win, rows - 2, cols - 2);
128             sigwinch = 0;
129             erase();
130         }
131
132         while ((ch = getch()) != ERR) {
133             madtty_keypress(rt, ch); /* pass the keypress for handling */
134             dirty = 1;
135         }
136
137         gettimeofday(&tv, NULL);
138         if (dirty && is_expired(tv, next)) {
139             madtty_draw(rt, term_win, 0, 0);
140             wrefresh(term_win);
141             dirty = 0;
142             next = timeval_add(tv, slice);
143         }
144     }
145
146     endwin();
147     return 0;
148 }