]> code.citadel.org Git - citadel.git/blob - citadel/screen.c
better curses compatibility, and a couple makefile/configure tweaks
[citadel.git] / citadel / screen.c
1 /* $Id$ */
2
3 /*
4  * Handle full-screen curses stuff
5  */
6
7 #include "sysdep.h"
8 #include "screen.h"
9 #include <stdio.h>
10 #include <signal.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #ifdef HAVE_VW_PRINTW
16 #define _vwprintw vw_printw
17 #else
18 /* SYSV style curses (Solaris, etc.) */
19 #define _vwprintw vwprintw
20 #endif
21 #ifndef HAVE_SNPRINTF
22 #include "snprintf.h"
23 #endif
24 #include "citadel.h"
25 #include "commands.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                 if (c == 7) beep();
326                 return ((waddch(mainwindow, c) == OK) ? c : EOF);
327         }
328 #endif
329         return putc(c, stdout);
330 }
331
332
333 int sln_putc(int c)
334 {
335 #ifdef HAVE_CURSES_H
336         if (statuswindow)
337                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
338 #endif
339         return putc(c, stdout);
340 }
341
342
343 int sln_putc_if(int c)
344 {
345 #ifdef HAVE_CURSES_H
346         if (statuswindow)
347                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
348 #endif
349         return 1;
350 }
351
352
353 /*
354  * scr_color() sets the window color for mainwindow
355  */
356 int scr_color(int colornum)
357 {
358 #ifdef HAVE_CURSES_H
359         if (mainwindow) {
360 #ifdef HAVE_WCOLOR_SET
361                 wcolor_set(mainwindow, (colornum & 7), NULL);
362 #else
363                 wattron(mainwindow, COLOR_PAIR((colornum & 7)));
364 #endif
365                 if (colornum & 8) {
366                         wattron(mainwindow, A_BOLD);
367                 } else {
368                         wattroff(mainwindow, A_BOLD);
369                 }
370                 return 1;
371         }
372 #endif
373         return 0;
374 }
375
376
377 void scr_flush(void)
378 {
379 #ifdef HAVE_CURSES_H
380         if (mainwindow)
381                 wrefresh(mainwindow);
382         else
383 #endif
384                 fflush(stdout);
385 }
386
387
388 void err_flush(void)
389 {
390 #ifdef HAVE_CURSES_H
391         if (mainwindow)         /* FIXME: error status window needed */
392                 wrefresh(mainwindow);
393         else
394 #endif
395                 fflush(stderr);
396 }
397
398
399 void sln_flush(void)
400 {
401 #ifdef HAVE_CURSES_H
402         if (statuswindow)
403                 wrefresh(statuswindow);
404         else
405 #endif
406                 fflush(stdout);
407 }
408
409 static volatile int caught_sigwinch = 0;
410
411 /*
412  * this is not supposed to be called from a signal handler.
413  */
414 int scr_set_windowsize()
415 {
416 #ifdef HAVE_CURSES_H
417         if (mainwindow && caught_sigwinch) {
418                 caught_sigwinch = 0;
419 #ifdef HAVE_RESIZETERM
420                 resizeterm(screenheight + 1, screenwidth);
421 #endif
422 #ifdef HAVE_WRESIZE
423                 wresize(mainwindow, screenheight, screenwidth);
424                 wresize(statuswindow, 1, screenwidth);
425 #endif
426                 mvwin(statuswindow, screenheight, 0);
427                 status_line(serv_info.serv_humannode, serv_info.serv_bbs_city,
428                             room_name, secure, -1);
429                 wnoutrefresh(mainwindow);
430                 wnoutrefresh(statuswindow);
431                 doupdate();
432                 return 1;
433         }
434 #endif /* HAVE_CURSES_H */
435         return 0;
436 }
437
438 /*
439  * scr_winch() handles window size changes from SIGWINCH
440  * resizes all our windows for us
441  */
442 RETSIGTYPE scr_winch(int signum)
443 {
444         /* if we receive this signal, we must be running
445            in a terminal that supports resizing. */
446         have_xterm = 1;
447         caught_sigwinch = 1;
448         check_screen_dims();
449         signal(SIGWINCH, scr_winch);
450 }
451
452
453 /*
454  * Initialize the window(s) we will be using.
455  */
456 void windows_new(void)
457 {
458 #ifdef HAVE_CURSES_H
459         register int x, y;
460
461         if (myscreen) {
462                 getmaxyx(stdscr, y, x);
463                 mainwindow = newwin(y - 1, x, 0, 0);
464                 screenwidth = x;
465                 screenheight = y - 1;
466                 immedok(mainwindow, FALSE);
467                 leaveok(mainwindow, FALSE);
468                 scrollok(mainwindow, TRUE);
469                 statuswindow = newwin(1, x, y - 1, 0);
470
471                 if (COLOR_PAIRS > 8)
472                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(8));
473                 else
474                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(DIM_WHITE));
475
476                 werase(statuswindow);
477                 immedok(statuswindow, FALSE);
478                 leaveok(statuswindow, FALSE);
479                 scrollok(statuswindow, FALSE);
480                 wrefresh(statuswindow);
481         }
482 #else /* HAVE_CURSES_H */
483
484 #endif /* HAVE_CURSES_H */
485 }
486
487
488 /*
489  * Deinitialize the window(s) we were using (at exit).
490  */
491 void windows_delete(void)
492 {
493 #ifdef HAVE_CURSES_H
494         if (mainwindow)
495                 delwin(mainwindow);
496         mainwindow = NULL;
497         if (statuswindow)
498                 delwin(statuswindow);
499         statuswindow = NULL;
500 #else /* HAVE_CURSES_H */
501
502 #endif /* HAVE_CURSES_H */
503 }