Back to index

citadel  8.12
screen.c
Go to the documentation of this file.
00001 /*
00002  * Screen output handling
00003  *
00004  * Copyright (c) 1987-2012 by the citadel.org team
00005  *
00006  * This program is open source software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License version 3.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 
00016 #include <stdlib.h>
00017 #include <unistd.h>
00018 #include <stdio.h>
00019 #include <signal.h>
00020 #include <string.h>
00021 #include <stdarg.h>
00022 #include <ctype.h>
00023 #include <sys/types.h>
00024 #include <sys/ioctl.h>
00025 #include "sysdep.h"
00026 #ifndef HAVE_SNPRINTF
00027 #include "snprintf.h"
00028 #endif
00029 #include <libcitadel.h>
00030 #include "citadel.h"
00031 #include "citadel_ipc.h"
00032 #include "citadel_decls.h"
00033 #include "commands.h"
00034 #include "screen.h"
00035 
00036 int enable_status_line = 0;
00037 char status_line[1024] = "     ";
00038 
00039 /* the default paginator prompt will be replaced by the server's prompt when we learn it */
00040 char *moreprompt = " -- more -- ";
00041 
00042 int screenheight = 24;
00043 int screenwidth = 80;
00044 int lines_printed = 0;
00045 int cols_printed = 0;
00046 
00047 extern int rc_ansi_color;
00048 extern int rc_prompt_control;
00049 void do_keepalive(void);
00050 
00051 /*
00052  * Attempt to discover the screen dimensions. 
00053  * WARNING: This is sometimes called from a signal handler.
00054  */
00055 void check_screen_dims(void)
00056 {
00057 #ifdef TIOCGWINSZ
00058        struct {
00059               unsigned short height;      /* rows */
00060               unsigned short width;       /* columns */
00061               unsigned short xpixels;
00062               unsigned short ypixels;     /* pixels */
00063        } xwinsz;
00064 
00065        if (ioctl(0, TIOCGWINSZ, &xwinsz) == 0) {
00066               if (xwinsz.height)
00067                      screenheight = (int) xwinsz.height;
00068               if (xwinsz.width)
00069                      screenwidth = (int) xwinsz.width;
00070        }
00071 #endif
00072 }
00073 
00074 
00075 /*
00076  * Initialize the screen
00077  */
00078 void screen_new(void)
00079 {
00080        send_ansi_detect();
00081        look_for_ansi();
00082        cls(0);
00083        color(DIM_WHITE);
00084 }
00085 
00086 
00087 
00088 /*
00089  * Beep.
00090  */
00091 void ctdl_beep(void) {
00092        putc(7, stdout);
00093 }
00094        
00095 
00096 
00097 
00098 /*
00099  * scr_printf() outputs to the terminal
00100  */
00101 int scr_printf(char *fmt, ...)
00102 {
00103        static char outbuf[4096];   /* static for performance -- not re-entrant -- change if needed */
00104        va_list ap;
00105        register int retval;
00106        int i, len;
00107 
00108        va_start(ap, fmt);
00109        retval = vsnprintf(outbuf, sizeof outbuf, fmt, ap);
00110        va_end(ap);
00111 
00112        len = strlen(outbuf);
00113        for (i=0; i<len; ++i) {
00114               scr_putc(outbuf[i]);
00115        }
00116        return retval;
00117 }
00118 
00119 
00120 /*
00121  * Read one character from the terminal
00122  */
00123 int scr_getc(int delay)
00124 {
00125        unsigned char buf;
00126 
00127        scr_flush();
00128 
00129        buf = '\0';
00130        if (!read (0, &buf, 1))
00131               logoff(NULL, 3);
00132 
00133        lines_printed = 0;
00134        return buf;
00135 }
00136 
00137 /*
00138  * Issue the paginator prompt (more / hit any key to continue)
00139  */
00140 void hit_any_key(void) {
00141        int a, b;
00142 
00143        color(COLOR_PUSH);
00144        color(DIM_RED);
00145        scr_printf("%s\r", moreprompt);
00146        color(COLOR_POP);
00147        b=inkey();
00148        for (a=0; a<screenwidth; ++a) {
00149               scr_putc(' ');
00150        }
00151        scr_printf("\r");
00152 
00153        if ( (rc_prompt_control == 1) || ((rc_prompt_control == 3) && (userflags & US_PROMPTCTL)) ) {
00154               if (b == 'q' || b == 'Q' || b == 's' || b == 'S') {
00155                      b = STOP_KEY;
00156               }
00157               if (b == 'n' || b == 'N') {
00158                      b = NEXT_KEY;
00159               }
00160        }
00161 
00162        if (b==NEXT_KEY) sigcaught = SIGINT;
00163        if (b==STOP_KEY) sigcaught = SIGQUIT;
00164 }
00165 
00166 
00167 /*
00168  * Output one character to the terminal
00169  */
00170 int scr_putc(int c)
00171 {
00172        /* handle tabs normally */
00173        if (c == '\t') {
00174               do {
00175                      scr_putc(' ');
00176               } while ((cols_printed % 8) != 0);
00177               return(c);
00178        }
00179 
00180        /* Output the character... */
00181        if (putc(c, stdout) == EOF) {
00182               logoff(NULL, 3);
00183        }
00184 
00185        if (c == '\n') {
00186               ++lines_printed;
00187               cols_printed = 0;
00188        }
00189        else if (c == '\r') {
00190               cols_printed = 0;
00191        }
00192        else if (isprint(c)) {
00193               ++cols_printed;
00194               if ((screenwidth > 0) && (cols_printed > screenwidth)) {
00195                      ++lines_printed;
00196                      cols_printed = 0;
00197               }
00198        }
00199 
00200        /* How many lines output before stopping for the paginator?
00201         * Depends on whether we are displaying a status line.
00202         */
00203        int height_offset = ( ((enable_color) && (screenwidth > 0) && (enable_status_line)) ? (3) : (2) ) ;
00204 
00205        /* Ok, go check it.  Stop and display the paginator prompt if necessary. */
00206        if ((screenheight > 0) && (lines_printed > (screenheight-height_offset))) {
00207               lines_printed = 0;
00208               hit_any_key();
00209               lines_printed = 0;
00210               cols_printed = 0;
00211        }
00212 
00213        return c;
00214 }
00215 
00216 void scr_flush(void)
00217 {
00218        if ((enable_color) && (screenwidth > 0) && (enable_status_line)) {
00219               if (strlen(status_line) < screenwidth) {
00220                      memset(&status_line[strlen(status_line)], 32, screenwidth - strlen(status_line));
00221               }
00222               printf("\033[s\033[1;1H\033[K\033[7m");
00223               fwrite(status_line, screenwidth, 1, stdout);
00224               printf("\033[27m\033[u");
00225        }
00226        fflush(stdout);
00227 }
00228 
00229 
00230 static volatile int caught_sigwinch = 0;
00231 
00232 
00233 /*
00234  * scr_winch() handles window size changes from SIGWINCH
00235  * resizes all our windows for us
00236  */
00237 RETSIGTYPE scr_winch(int signum)
00238 {
00239        /* if we receive this signal, we must be running
00240         * in a terminal that supports resizing.
00241         */
00242        caught_sigwinch = 1;
00243        check_screen_dims();
00244        signal(SIGWINCH, scr_winch);
00245 }
00246 
00247 
00248 
00249 /*
00250  * Display a 3270-style "wait" indicator at the bottom of the screen
00251  */
00252 void scr_wait_indicator(int state) {
00253        int sp = (screenwidth - 2);
00254 
00255        if (!enable_status_line) return;
00256 
00257        if (screenwidth > 0) {
00258               switch (state) {
00259                      default:
00260                      case 0:        /* Idle */
00261                             status_line[sp] = ' ';
00262                             break;
00263                      case 1:        /* Waiting */
00264                             status_line[sp] = 'X';
00265                             break;
00266                      case 2:        /* Receiving */
00267                             status_line[sp] = '<';
00268                             break;
00269                      case 3:        /* Sending */
00270                             status_line[sp] = '>';
00271                             break;
00272               }
00273               scr_flush();
00274        }
00275 }
00276