]> code.citadel.org Git - citadel.git/blob - citadel/screen.c
* screen.c: fix lack of beeps 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                 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                 resizeterm(screenheight + 1, screenwidth);
420                 wresize(mainwindow, screenheight, screenwidth);
421                 wresize(statuswindow, 1, screenwidth);
422                 mvwin(statuswindow, screenheight, 0);
423                 status_line(serv_info.serv_humannode, serv_info.serv_bbs_city,
424                             room_name, secure, -1);
425                 wnoutrefresh(mainwindow);
426                 wnoutrefresh(statuswindow);
427                 doupdate();
428                 return 1;
429         }
430 #endif /* HAVE_CURSES_H */
431         return 0;
432 }
433
434 /*
435  * scr_winch() handles window size changes from SIGWINCH
436  * resizes all our windows for us
437  */
438 RETSIGTYPE scr_winch(int signum)
439 {
440         /* if we receive this signal, we must be running
441            in a terminal that supports resizing. */
442         have_xterm = 1;
443         caught_sigwinch = 1;
444         check_screen_dims();
445         signal(SIGWINCH, scr_winch);
446 }
447
448
449 /*
450  * Initialize the window(s) we will be using.
451  */
452 void windows_new(void)
453 {
454 #ifdef HAVE_CURSES_H
455         register int x, y;
456
457         if (myscreen) {
458                 getmaxyx(stdscr, y, x);
459                 mainwindow = newwin(y - 1, x, 0, 0);
460                 screenwidth = x;
461                 screenheight = y - 1;
462                 immedok(mainwindow, FALSE);
463                 leaveok(mainwindow, FALSE);
464                 scrollok(mainwindow, TRUE);
465                 statuswindow = newwin(1, x, y - 1, 0);
466
467                 if (COLOR_PAIRS > 8)
468                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(8));
469                 else
470                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(DIM_WHITE));
471
472                 werase(statuswindow);
473                 immedok(statuswindow, FALSE);
474                 leaveok(statuswindow, FALSE);
475                 scrollok(statuswindow, FALSE);
476                 wrefresh(statuswindow);
477         }
478 #else /* HAVE_CURSES_H */
479
480 #endif /* HAVE_CURSES_H */
481 }
482
483
484 /*
485  * Deinitialize the window(s) we were using (at exit).
486  */
487 void windows_delete(void)
488 {
489 #ifdef HAVE_CURSES_H
490         if (mainwindow)
491                 delwin(mainwindow);
492         mainwindow = NULL;
493         if (statuswindow)
494                 delwin(statuswindow);
495         statuswindow = NULL;
496 #else /* HAVE_CURSES_H */
497
498 #endif /* HAVE_CURSES_H */
499 }