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