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