]> code.citadel.org Git - citadel.git/blob - citadel/screen.c
support window resizing in curses mode
[citadel.git] / citadel / screen.c
1 /* $Id$ */
2
3 /*
4  * Handle full-screen curses stuff
5  */
6
7 #include "sysdep.h"
8 #include <stdio.h>
9 #include <signal.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #ifdef HAVE_VW_PRINTW
15 #define _vwprintw vw_printw
16 #else
17 /* SYSV style curses (Solaris, etc.) */
18 #define _vwprintw vwprintw
19 #endif
20 #ifndef HAVE_SNPRINTF
21 #include "snprintf.h"
22 #endif
23 #include "citadel.h"
24 #include "commands.h"
25 #include "screen.h"
26 #include "citadel_decls.h"
27
28 #ifdef HAVE_CURSES_H
29 static SCREEN *myscreen = NULL;
30 static WINDOW *mainwindow = NULL;
31 static WINDOW *statuswindow = NULL;
32
33 char rc_screen;
34 char arg_screen;
35
36 extern int screenheight;
37 extern int screenwidth;
38 extern int rc_ansi_color;
39 extern void check_screen_dims(void);
40 #endif
41
42 void do_keepalive(void);
43
44
45 int is_curses_enabled(void) {
46 #ifdef HAVE_CURSES_H
47         return mainwindow != NULL;
48 #else
49         return 0;
50 #endif
51 }
52
53 /*
54  * status_line() is a convenience function for writing a "typical"
55  * status line to the window.
56  */
57 void status_line(const char *humannode, const char *bbs_city,
58                  const char *room_name, int secure, int newmailcount)
59 {
60 #ifdef HAVE_CURSES_H
61         if (statuswindow) {
62                 if (secure) {
63                         sln_printf("Encrypted ");
64                         waddch(statuswindow, ACS_VLINE);
65                         waddch(statuswindow, ' ');
66                 }
67                 if (room_name)
68                         sln_printf("%s on ", room_name);
69                 if (humannode)
70                         sln_printf("%s ", humannode);
71                 if (newmailcount > -1) {
72                         waddch(statuswindow, ACS_VLINE);
73                         sln_printf(" Mail: %d new ", newmailcount);
74                 }
75                 sln_printf("\n");
76         }
77 #endif /* HAVE_CURSES_H */
78 }
79
80
81 /*
82  * Initialize the screen.  If newterm() fails, myscreen will be NULL and
83  * further handlers will assume we should be in line mode.
84  */
85 void screen_new(void)
86 {
87 #ifdef HAVE_CURSES_H
88         if (arg_screen != RC_NO && rc_screen != RC_NO)
89                 myscreen = newterm(NULL, stdout, stdin);
90         if (myscreen) {
91                 cbreak();
92                 noecho();
93                 nonl();
94                 intrflush(stdscr, FALSE);
95                 keypad(stdscr, TRUE);
96                 /* Setup all our colors */
97                 start_color();
98                 if (rc_ansi_color)
99                         enable_color = 1;
100                 /*init_pair(DIM_BLACK, COLOR_BLACK, COLOR_BLACK);*/
101                 init_pair(DIM_RED, COLOR_RED, COLOR_BLACK);
102                 init_pair(DIM_GREEN, COLOR_GREEN, COLOR_BLACK);
103                 init_pair(DIM_YELLOW, COLOR_YELLOW, COLOR_BLACK);
104                 init_pair(DIM_BLUE, COLOR_BLUE, COLOR_BLACK);
105                 init_pair(DIM_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
106                 init_pair(DIM_CYAN, COLOR_CYAN, COLOR_BLACK);
107                 init_pair(DIM_WHITE, COLOR_WHITE, COLOR_BLACK);
108
109                 if (COLOR_PAIRS > 8)
110                         init_pair(8, COLOR_WHITE, COLOR_BLUE);
111         } else
112 #endif /* HAVE_CURSES_H */
113         {
114                 send_ansi_detect();
115                 look_for_ansi();
116                 cls(0);
117                 color(DIM_WHITE);
118         }
119         screen_set();
120         windows_new();
121 }
122
123
124 /*
125  * Kill the screen completely (used at exit).  It is safe to call this
126  * function more than once.
127  */
128 void screen_delete(void)
129 {
130         windows_delete();
131         screen_reset();
132 #ifdef HAVE_CURSES_H
133         if (myscreen)
134                 delscreen(myscreen);
135         myscreen = NULL;
136 #endif
137 }
138
139
140 /*
141  * Set screen/IO parameters, e.g. at start of program or return from external
142  * program run.
143  */
144 int screen_set(void)
145 {
146 #ifdef HAVE_CURSES_H
147         if (myscreen) {
148                 set_term(myscreen);
149                 wrefresh(curscr);
150                 return 1;
151         }
152 #endif /* HAVE_CURSES_H */
153         return 0;
154 }
155
156
157 /*
158  * Reset screen/IO parameters, e.g. at exit or fork of external program.
159  */
160 int screen_reset(void)
161 {
162 #ifdef HAVE_CURSES_H
163         if (myscreen) {
164                 endwin();
165                 return 1;
166         }
167 #endif /* HAVE_CURSES_H */
168         return 0;
169 }
170
171
172 /*
173  * scr_printf() outputs to the main window (or screen if not in curses)
174  */
175 int scr_printf(char *fmt, ...)
176 {
177         va_list ap;
178         register int retval;
179
180         va_start(ap, fmt);
181 #ifdef HAVE_CURSES_H
182         if (mainwindow) {
183                 retval = _vwprintw(mainwindow, fmt, ap);
184         } else
185 #endif
186                 retval = vprintf(fmt, ap);
187         va_end(ap);
188         return retval;
189 }
190
191
192 /*
193  * err_printf() outputs to error status window (or stderr if not in curses)
194  */
195 int err_printf(char *fmt, ...)
196 {
197         va_list ap;
198         register int retval;
199
200         va_start(ap, fmt);
201 #ifdef HAVE_CURSES_H
202         if (mainwindow) {               /* FIXME: direct to error window */
203                 retval = _vwprintw(mainwindow, fmt, ap);
204                 if (fmt[strlen(fmt) - 1] == '\n')
205                         wrefresh(mainwindow);
206         } else
207 #endif
208                 retval = vfprintf(stderr, fmt, ap);
209         va_end(ap);
210         return retval;
211 }
212
213
214 /*
215  * sln_printf() outputs to error status window (or stderr if not in curses)
216  */
217 int sln_printf(char *fmt, ...)
218 {
219         va_list ap;
220         register int retval;
221 #ifdef HAVE_CURSES_H
222         static char buf[4096];
223 #endif
224
225         va_start(ap, fmt);
226 #ifdef HAVE_CURSES_H
227         if (statuswindow) {
228                 register char *i;
229                 
230                 retval = vsnprintf(buf, 4096, fmt, ap);
231                 for (i = buf; *i; i++) {
232                         if (*i == '\r' || *i == '\n')
233                                 wclrtoeol(statuswindow);
234                         sln_putc(*i);
235                         if (*i == '\r' || *i == '\n') {
236                                 wrefresh(statuswindow);
237                                 mvwinch(statuswindow, 0, 0);
238                         }
239                 }
240         } else
241 #endif
242                 retval = vprintf(fmt, ap);
243         va_end(ap);
244         return retval;
245 }
246
247
248 /*
249  * sln_printf_if() outputs to status window, no output if not in curses
250  */
251 int sln_printf_if(char *fmt, ...)
252 {
253         register int retval = 1;
254 #ifdef HAVE_CURSES_H
255         static char buf[4096];
256         va_list ap;
257
258         va_start(ap, fmt);
259         if (statuswindow) {
260                 register char *i;
261                 
262                 retval = vsnprintf(buf, 4096, fmt, ap);
263                 for (i = buf; *i; i++) {
264                         if (*i == '\r' || *i == '\n')
265                                 wclrtoeol(statuswindow);
266                         sln_putc(*i);
267                         if (*i == '\r' || *i == '\n') {
268                                 wrefresh(statuswindow);
269                                 mvwinch(statuswindow, 0, 0);
270                         }
271                 }
272         }
273         va_end(ap);
274 #endif
275         return retval;
276 }
277
278
279 int scr_getc(int delay)
280 {
281   char buf;
282
283 #ifdef HAVE_CURSES_H
284         if (mainwindow) {
285                 wtimeout(mainwindow, delay);
286                 return wgetch(mainwindow);
287         }
288 #endif
289
290   buf = '\0';
291   read (0, &buf, 1);
292         return buf;
293 }
294
295 /* the following is unused and looks broken, but there may
296    be some input problems still lurking in curses mode, so
297    i'll leave it blocked out for now for informational
298    purposes. */
299 #if 0
300 int scr_blockread(void)
301   {
302     int a = 0;
303 #ifdef HAVE_CURSES_H
304     wtimeout(mainwindow, S_KEEPALIVE); 
305     while (1)
306       {
307         do_keepalive();
308         a = wgetch(mainwindow); /* will block for food */
309         if (a != ERR)
310           break;
311         /* a = scr_getc(); */
312       }
313 #endif
314     return a;
315   }
316 #endif /* 0 */
317
318 /*
319  * scr_putc() outputs a single character
320  */
321 int scr_putc(int c)
322 {
323 #ifdef HAVE_CURSES_H
324         if (mainwindow)
325                 return ((waddch(mainwindow, c) == OK) ? c : EOF);
326 #endif
327         return putc(c, stdout);
328 }
329
330
331 int sln_putc(int c)
332 {
333 #ifdef HAVE_CURSES_H
334         if (statuswindow)
335                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
336 #endif
337         return putc(c, stdout);
338 }
339
340
341 int sln_putc_if(int c)
342 {
343 #ifdef HAVE_CURSES_H
344         if (statuswindow)
345                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
346 #endif
347         return 1;
348 }
349
350
351 /*
352  * scr_color() sets the window color for mainwindow
353  */
354 int scr_color(int colornum)
355 {
356 #ifdef HAVE_CURSES_H
357         if (mainwindow) {
358 #ifdef HAVE_WCOLOR_SET
359                 wcolor_set(mainwindow, (colornum & 7), NULL);
360 #else
361                 wattron(mainwindow, COLOR_PAIR((colornum & 7)));
362 #endif
363                 if (colornum & 8) {
364                         wattron(mainwindow, A_BOLD);
365                 } else {
366                         wattroff(mainwindow, A_BOLD);
367                 }
368                 return 1;
369         }
370 #endif
371         return 0;
372 }
373
374
375 void scr_flush(void)
376 {
377 #ifdef HAVE_CURSES_H
378         if (mainwindow)
379                 wrefresh(mainwindow);
380         else
381 #endif
382                 fflush(stdout);
383 }
384
385
386 void err_flush(void)
387 {
388 #ifdef HAVE_CURSES_H
389         if (mainwindow)         /* FIXME: error status window needed */
390                 wrefresh(mainwindow);
391         else
392 #endif
393                 fflush(stderr);
394 }
395
396
397 void sln_flush(void)
398 {
399 #ifdef HAVE_CURSES_H
400         if (statuswindow)
401                 wrefresh(statuswindow);
402         else
403 #endif
404                 fflush(stdout);
405 }
406
407 static volatile int caught_sigwinch = 0;
408
409 /*
410  * this is not supposed to be called from a signal handler.
411  */
412 int scr_set_windowsize()
413 {
414 #ifdef HAVE_CURSES_H
415         if (mainwindow && caught_sigwinch) {
416                 caught_sigwinch = 0;
417                 resizeterm(screenheight + 1, screenwidth);
418                 wresize(mainwindow, screenheight, screenwidth);
419                 wresize(statuswindow, 1, screenwidth);
420                 mvwin(statuswindow, screenheight, 0);
421                 status_line(serv_info.serv_humannode, serv_info.serv_bbs_city,
422                             room_name, secure, -1);
423                 wnoutrefresh(mainwindow);
424                 wnoutrefresh(statuswindow);
425                 doupdate();
426                 return 1;
427         }
428 #endif /* HAVE_CURSES_H */
429         return 0;
430 }
431
432 /*
433  * scr_winch() handles window size changes from SIGWINCH
434  * resizes all our windows for us
435  */
436 RETSIGTYPE scr_winch(int signum)
437 {
438         /* if we receive this signal, we must be running
439            in a terminal that supports resizing. */
440         have_xterm = 1;
441         caught_sigwinch = 1;
442         check_screen_dims();
443         signal(SIGWINCH, scr_winch);
444 }
445
446
447 /*
448  * Initialize the window(s) we will be using.
449  */
450 void windows_new(void)
451 {
452 #ifdef HAVE_CURSES_H
453         register int x, y;
454
455         if (myscreen) {
456                 getmaxyx(stdscr, y, x);
457                 mainwindow = newwin(y - 1, x, 0, 0);
458                 screenwidth = x;
459                 screenheight = y - 1;
460                 immedok(mainwindow, FALSE);
461                 leaveok(mainwindow, FALSE);
462                 scrollok(mainwindow, TRUE);
463                 statuswindow = newwin(1, x, y - 1, 0);
464
465                 if (COLOR_PAIRS > 8)
466                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(8));
467                 else
468                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(DIM_WHITE));
469
470                 werase(statuswindow);
471                 immedok(statuswindow, FALSE);
472                 leaveok(statuswindow, FALSE);
473                 scrollok(statuswindow, FALSE);
474                 wrefresh(statuswindow);
475         }
476 #else /* HAVE_CURSES_H */
477
478 #endif /* HAVE_CURSES_H */
479 }
480
481
482 /*
483  * Deinitialize the window(s) we were using (at exit).
484  */
485 void windows_delete(void)
486 {
487 #ifdef HAVE_CURSES_H
488         if (mainwindow)
489                 delwin(mainwindow);
490         mainwindow = NULL;
491         if (statuswindow)
492                 delwin(statuswindow);
493         statuswindow = NULL;
494 #else /* HAVE_CURSES_H */
495
496 #endif /* HAVE_CURSES_H */
497 }