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