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