]> code.citadel.org Git - citadel.git/blob - citadel/screen.c
* Don't run the wait indicator when in an external editor
[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 /*
175  * Set screen/IO parameters, e.g. at start of program or return from external
176  * program run.
177  */
178 int screen_set(void)
179 {
180 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
181         if (myscreen) {
182                 set_term(myscreen);
183                 wrefresh(curscr);
184                 return 1;
185         }
186 #endif /* HAVE_CURSES_H */
187         return 0;
188 }
189
190
191 /*
192  * Reset screen/IO parameters, e.g. at exit or fork of external program.
193  */
194 int screen_reset(void)
195 {
196 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
197         if (myscreen) {
198                 endwin();
199                 return 1;
200         }
201 #endif /* HAVE_CURSES_H */
202         return 0;
203 }
204
205
206 /*
207  * scr_printf() outputs to the main window (or screen if not in curses)
208  */
209 int scr_printf(char *fmt, ...)
210 {
211         va_list ap;
212         register int retval;
213
214         va_start(ap, fmt);
215 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
216         if (mainwindow) {
217                 retval = _vwprintw(mainwindow, fmt, ap);
218         } else
219 #endif
220                 retval = vprintf(fmt, ap);
221         va_end(ap);
222         return retval;
223 }
224
225
226 /*
227  * err_printf() outputs to error status window (or stderr if not in curses)
228  */
229 int err_printf(char *fmt, ...)
230 {
231         va_list ap;
232         register int retval;
233
234         va_start(ap, fmt);
235 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
236         if (mainwindow) {               /* FIXME: direct to error window */
237                 retval = _vwprintw(mainwindow, fmt, ap);
238                 if (fmt[strlen(fmt) - 1] == '\n')
239                         wrefresh(mainwindow);
240         } else
241 #endif
242                 retval = vfprintf(stderr, fmt, ap);
243         va_end(ap);
244         return retval;
245 }
246
247
248 /*
249  * sln_printf() outputs to error status window (or stderr if not in curses)
250  */
251 int sln_printf(char *fmt, ...)
252 {
253         va_list ap;
254         register int retval;
255 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
256         static char buf[4096];
257 #endif
258
259         va_start(ap, fmt);
260 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
261         if (statuswindow) {
262                 register char *i;
263                 
264                 retval = vsnprintf(buf, 4096, fmt, ap);
265                 for (i = buf; *i; i++) {
266                         if (*i == '\r' || *i == '\n')
267                                 wclrtoeol(statuswindow);
268                         sln_putc(*i);
269                         if (*i == '\r' || *i == '\n') {
270                                 wrefresh(statuswindow);
271                                 mvwinch(statuswindow, 0, 0);
272                         }
273                 }
274         } else
275 #endif
276                 retval = vprintf(fmt, ap);
277         va_end(ap);
278         return retval;
279 }
280
281
282 /*
283  * sln_printf_if() outputs to status window, no output if not in curses
284  */
285 int sln_printf_if(char *fmt, ...)
286 {
287         register int retval = 1;
288 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
289         static char buf[4096];
290         va_list ap;
291
292         va_start(ap, fmt);
293         if (statuswindow) {
294                 register char *i;
295                 
296                 retval = vsnprintf(buf, 4096, fmt, ap);
297                 for (i = buf; *i; i++) {
298                         if (*i == '\r' || *i == '\n')
299                                 wclrtoeol(statuswindow);
300                         sln_putc(*i);
301                         if (*i == '\r' || *i == '\n') {
302                                 wrefresh(statuswindow);
303                                 mvwinch(statuswindow, 0, 0);
304                         }
305                 }
306         }
307         va_end(ap);
308 #endif
309         return retval;
310 }
311
312
313 int scr_getc(int delay)
314 {
315   unsigned char buf;
316
317 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
318         if (mainwindow) {
319                 wtimeout(mainwindow, delay);
320                 return wgetch(mainwindow);
321         }
322 #endif
323
324         buf = '\0';
325         read (0, &buf, 1);
326         return buf;
327 }
328
329 /* the following is unused and looks broken, but there may
330    be some input problems still lurking in curses mode, so
331    i'll leave it blocked out for now for informational
332    purposes. */
333 #if 0
334 int scr_blockread(void)
335   {
336     int a = 0;
337 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
338     wtimeout(mainwindow, S_KEEPALIVE); 
339     while (1)
340       {
341         do_keepalive();
342         a = wgetch(mainwindow); /* will block for food */
343         if (a != ERR)
344           break;
345         /* a = scr_getc(); */
346       }
347 #endif
348     return a;
349   }
350 #endif /* 0 */
351
352 /*
353  * scr_putc() outputs a single character
354  */
355 int scr_putc(int c)
356 {
357 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
358         if (mainwindow) {
359                 if (c == 7) beep();
360                 return ((waddch(mainwindow, c) == OK) ? c : EOF);
361         }
362 #endif
363         return putc(c, stdout);
364 }
365
366
367 int sln_putc(int c)
368 {
369 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
370         if (statuswindow)
371                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
372 #endif
373         return putc(c, stdout);
374 }
375
376
377 int sln_putc_if(int c)
378 {
379 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
380         if (statuswindow)
381                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
382 #endif
383         return 1;
384 }
385
386
387 /*
388  * scr_color() sets the window color for mainwindow
389  */
390 int scr_color(int colornum)
391 {
392 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
393         if (mainwindow) {
394 #ifdef HAVE_WCOLOR_SET
395                 wcolor_set(mainwindow, (colornum & 7), NULL);
396 #else
397                 wattron(mainwindow, COLOR_PAIR((colornum & 7)));
398 #endif
399                 if (colornum & 8) {
400                         wattron(mainwindow, A_BOLD);
401                 } else {
402                         wattroff(mainwindow, A_BOLD);
403                 }
404                 return 1;
405         }
406 #endif
407         return 0;
408 }
409
410
411 void scr_flush(void)
412 {
413 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
414         if (mainwindow)
415                 wrefresh(mainwindow);
416         else
417 #endif
418                 fflush(stdout);
419 }
420
421
422 void err_flush(void)
423 {
424 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
425         if (mainwindow)         /* FIXME: error status window needed */
426                 wrefresh(mainwindow);
427         else
428 #endif
429                 fflush(stderr);
430 }
431
432
433 void sln_flush(void)
434 {
435 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
436         if (statuswindow)
437                 wrefresh(statuswindow);
438         else
439 #endif
440                 fflush(stdout);
441 }
442
443 static volatile int caught_sigwinch = 0;
444
445 /*
446  * this is not supposed to be called from a signal handler.
447  */
448 int scr_set_windowsize()
449 {
450 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
451         if (mainwindow && caught_sigwinch) {
452                 caught_sigwinch = 0;
453 #ifdef HAVE_RESIZETERM
454                 resizeterm(screenheight + 1, screenwidth);
455 #endif
456 #ifdef HAVE_WRESIZE
457                 wresize(mainwindow, screenheight, screenwidth);
458                 wresize(statuswindow, 1, screenwidth);
459 #endif
460                 mvwin(statuswindow, screenheight, 0);
461                 status_line(serv_info.serv_humannode, serv_info.serv_bbs_city,
462                             room_name, secure, -1);
463                 wnoutrefresh(mainwindow);
464                 wnoutrefresh(statuswindow);
465                 doupdate();
466                 return 1;
467         }
468 #endif /* HAVE_CURSES_H */
469         return 0;
470 }
471
472 /*
473  * scr_winch() handles window size changes from SIGWINCH
474  * resizes all our windows for us
475  */
476 RETSIGTYPE scr_winch(int signum)
477 {
478         /* if we receive this signal, we must be running
479            in a terminal that supports resizing. */
480         have_xterm = 1;
481         caught_sigwinch = 1;
482         check_screen_dims();
483         signal(SIGWINCH, scr_winch);
484 }
485
486
487 /*
488  * Initialize the window(s) we will be using.
489  */
490 void windows_new(void)
491 {
492 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
493         register int x, y;
494
495         if (myscreen) {
496                 getmaxyx(stdscr, y, x);
497                 mainwindow = newwin(y - 1, x, 0, 0);
498                 screenwidth = x;
499                 screenheight = y - 1;
500                 immedok(mainwindow, FALSE);
501                 leaveok(mainwindow, FALSE);
502                 scrollok(mainwindow, TRUE);
503                 statuswindow = newwin(1, x, y - 1, 0);
504
505                 if (COLOR_PAIRS > 8)
506                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(8));
507                 else
508                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(DIM_WHITE));
509
510                 werase(statuswindow);
511                 immedok(statuswindow, FALSE);
512                 leaveok(statuswindow, FALSE);
513                 scrollok(statuswindow, FALSE);
514                 wrefresh(statuswindow);
515         }
516 #else /* HAVE_CURSES_H */
517
518 #endif /* HAVE_CURSES_H */
519 }
520
521
522 /*
523  * Deinitialize the window(s) we were using (at exit).
524  */
525 void windows_delete(void)
526 {
527 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
528         if (mainwindow)
529                 delwin(mainwindow);
530         mainwindow = NULL;
531         if (statuswindow)
532                 delwin(statuswindow);
533         statuswindow = NULL;
534 #else /* HAVE_CURSES_H */
535
536 #endif /* HAVE_CURSES_H */
537 }