Logo Search packages:      
Sourcecode: xawtv version File versions  Download package

vbi-tty.c

/*
 * vbi-tty  --  terminal videotext browser
 *
 *   (c) 2002 Gerd Knorr <kraxel@bytesex.org>
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <iconv.h>
#include <locale.h>
#include <langinfo.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#include <linux/fb.h>

#include "vbi-data.h"
#include "vbi-tty.h"
#include "fbtools.h"

/* --------------------------------------------------------------------- */

struct termios  saved_attributes;
int             saved_fl;

static void tty_raw(void)
{
    struct termios tattr;
    
    fcntl(0,F_GETFL,&saved_fl);
    tcgetattr (0, &saved_attributes);
    
    fcntl(0,F_SETFL,O_NONBLOCK);
    memcpy(&tattr,&saved_attributes,sizeof(struct termios));
    tattr.c_lflag &= ~(ICANON|ECHO);
    tattr.c_cc[VMIN] = 1;
    tattr.c_cc[VTIME] = 0;
    tcsetattr (0, TCSAFLUSH, &tattr);
}

static void tty_restore(void)
{
    fcntl(0,F_SETFL,saved_fl);
    tcsetattr (0, TCSANOW, &saved_attributes);
}

/* FIXME: Yes, I know, hardcoding ANSI sequences is bad.  ncurses
 * can't handle multibyte locales like UTF-8 not yet, that's why that
 * dirty hack for now ... */
static void tty_clear(void)
{
    fprintf(stderr,"\033[H\033[2J");
}

static void tty_goto(int x, int y)
{
    fprintf(stderr,"\033[%d;%dH",y,x);
}

/* --------------------------------------------------------------------- */

static int have_fb = 0;
static int fb_fmt  = VBI_PIXFMT_RGBA32_LE;
static int switch_last;

static void fb_clear(void)
{
    fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
}

/* --------------------------------------------------------------------- */

struct vbi_tty {
    struct vbi_state  *vbi;
    struct vbi_page   pg;
    int               pgno,subno;
    int               newpage;
};

static void
vbi_fix_head(struct vbi_tty *tty, struct vbi_char *ch)
{
    int showno,showsub,red,i;

    showno  = tty->pg.pgno;
    showsub = tty->pg.subno;
    red     = 0;
    if (0 == showno) {
      showno  = tty->pgno;
      showsub = 0;
      red     = 1;
    }
    if (tty->newpage) {
      showno  = tty->newpage;
      showsub = 0;
      red     = 1;
    }

    for (i = 1; i <= 6; i++)
      ch[i].unicode = ' ';
    if (showno >= 0x100)
      ch[1].unicode = '0' + ((showno >> 8) & 0xf);
    if (showno >= 0x10)
      ch[2].unicode = '0' + ((showno >> 4) & 0xf);
    if (showno >= 0x1)
      ch[3].unicode = '0' + ((showno >> 0) & 0xf);
    if (showsub) {
      ch[4].unicode = '/';
      ch[5].unicode = '0' + ((showsub >> 4) & 0xf);
      ch[6].unicode = '0' + ((showsub >> 0) & 0xf);
    }
    if (red) {
      ch[1].foreground = VBI_RED;
      ch[2].foreground = VBI_RED;
      ch[3].foreground = VBI_RED;
    }
}

static void
vbi_render_page(struct vbi_tty *tty)
{
    char *data;
    int len;

    data = malloc(25*41*24);
    vbi_fetch_vt_page(tty->vbi->dec,&tty->pg,tty->pgno,tty->subno,
                  VBI_WST_LEVEL_1p5,25,1);
    vbi_fix_head(tty,tty->pg.text);
    if (have_fb) {
      vbi_draw_vt_page_region(&tty->pg, fb_fmt,
                        fb_mem + fb_mem_offset,
                        fb_fix.line_length,
                        0,0,
                        tty->pg.columns, tty->pg.rows,
                        0,1);
      
    } else {
      len = vbi_export_txt(data,nl_langinfo(CODESET),25*41*8,
                       &tty->pg,&vbi_fullrect,VBI_ANSICOLOR);
      tty_goto(0,0);
      fwrite(data,len,1,stderr);
      tty_goto(42,0);
      free(data);
    }
}

static void
vbi_render_head(struct vbi_tty *tty, int pgno, int subno)
{
    static struct vbi_rect head = {
      x1:  0,  y1:  0,  x2: 41,  y2:  1,
    };
    struct vbi_page pg;
    char *data;
    int len;

    data = malloc(41*24);
    memset(&pg,0,sizeof(pg));
    vbi_fetch_vt_page(tty->vbi->dec,&pg,pgno,subno,
                  VBI_WST_LEVEL_1p5,1,1);
    vbi_fix_head(tty,pg.text);
    if (have_fb) {
      vbi_draw_vt_page_region(&pg, fb_fmt,
                        fb_mem + fb_mem_offset,
                        fb_fix.line_length,
                        0,0,
                        pg.columns, 1,
                        0,1);
    } else {
      len = vbi_export_txt(data,nl_langinfo(CODESET),41*8,
                       &pg,&head,VBI_ANSICOLOR);
      tty_goto(0,0);
      fwrite(data,len,1,stderr);
      tty_goto(42,0);
      free(data);
    }
}

static void
vbi_newdata(struct vbi_event *ev, void *user)
{
    struct vbi_tty *tty = user;
    
    switch (ev->type) {
    case VBI_EVENT_TTX_PAGE:
      if (tty->pgno  == ev->ev.ttx_page.pgno &&
          (tty->subno == ev->ev.ttx_page.subno ||
           tty->subno == VBI_ANY_SUBNO)) {
          vbi_render_page(tty);
      } else {
          vbi_render_head(tty,
                      ev->ev.ttx_page.pgno,
                      ev->ev.ttx_page.subno);
      }
      break;
    }
}

static void
vbi_setpage(struct vbi_tty *tty, int pgno, int subno)
{
    tty->pgno = pgno;
    tty->subno = subno;
    tty->newpage = 0;
    memset(&tty->pg,0,sizeof(struct vbi_page));
    vbi_fetch_vt_page(tty->vbi->dec,&tty->pg,tty->pgno,tty->subno,
                  VBI_WST_LEVEL_1p5,25,1);
    vbi_render_page(tty);
}

/* --------------------------------------------------------------------- */

void vbi_tty(char *device, int debug, int sim)
{
    struct vbi_state  *vbi;
    struct vbi_tty    *tty;
    fd_set            set;
    struct winsize    win;
    struct timeval    tv;
    char              key[11];
    int               rc,subno,last;

    setlocale(LC_ALL,"");
    vbi = vbi_open(device,debug,sim);
    if (NULL == vbi)
      exit(1);

    if (0 /* 0 == fb_probe() */ ) {
      have_fb = 1;
      fb_init(NULL,NULL,0);
      fb_catch_exit_signals();
      fb_switch_init();
      switch_last = fb_switch_state;
    } else {
      if (-1 != ioctl(0,TIOCGWINSZ,&win) && win.ws_row < 26) {
          fprintf(stderr,"Terminal too small (need 26 rows, have %d)\n",
                win.ws_row);
          exit(1);
      }
    }
    tty_raw();
    have_fb ? fb_clear() : tty_clear();

    tty = malloc(sizeof(*tty));
    memset(tty,0,sizeof(*tty));
    tty->vbi = vbi;
    vbi_event_handler_add(vbi->dec,~0,vbi_newdata,tty);
    vbi_setpage(tty,0x100,VBI_ANY_SUBNO);

    for (last = 0; !last;) {
      FD_ZERO(&set);
      FD_SET(0,&set);
      FD_SET(vbi->fd,&set);
      tv.tv_sec  = 1;
      tv.tv_usec = 0;
      rc = select(vbi->fd+1,&set,NULL,NULL,&tv);
      if (-1 == rc) {
          tty_restore();
          if (have_fb)
            fb_cleanup();
          perror("select");
          exit(1);
      }
      if (0 == rc) {
          if (have_fb)
            fb_cleanup();
          tty_restore();
          fprintf(stderr,"oops: timeout\n");
          exit(1);
      }
      if (FD_ISSET(0,&set)) {
          /* tty input */
          rc = read(0, key, 10);
          key[rc] = 0;
          if (1 == rc) {
            switch (key[0]) {
            case 'q':
            case 'Q':
                /* quit */
                last = 1;
                break;
            case 'L' & 0x1f:
                /* refresh */
                have_fb ? fb_clear() : tty_clear();
                vbi_render_page(tty);
                break;
            case 'i':
            case 'I':
                /* index */
                vbi_setpage(tty,0x100,VBI_ANY_SUBNO);
                break;
            case ' ':
            case 'l':
            case 'L':
                /* next page */
                vbi_setpage(tty,vbi_calc_page(tty->pgno,+1),VBI_ANY_SUBNO);
                break;
            case '\x7f':
            case 'h':
            case 'H':
                /* prev page */
                vbi_setpage(tty,vbi_calc_page(tty->pgno,-1),VBI_ANY_SUBNO);
                break;
            case 'k':
            case 'K':
                /* next subpage */
                subno = (tty->subno != VBI_ANY_SUBNO) ?
                  tty->subno : tty->pg.subno;
                subno = vbi_calc_subpage(tty->vbi->dec,tty->pgno,subno,+1);
                vbi_setpage(tty,tty->pgno,subno);
                break;
            case 'j':
            case 'J':
                /* prev subpage */
                subno = (tty->subno != VBI_ANY_SUBNO) ?
                  tty->subno : tty->pg.subno;
                subno = vbi_calc_subpage(tty->vbi->dec,tty->pgno,subno,-1);
                vbi_setpage(tty,tty->pgno,subno);
                break;
            default:
                if (key[0] >= '0'  &&  key[0] <= '9') {
                  tty->newpage *= 16;
                  tty->newpage += key[0] - '0';
                  if (tty->newpage >= 0x100)
                      vbi_setpage(tty,tty->newpage,VBI_ANY_SUBNO);
                }
            }
          }
      }
      if (FD_ISSET(vbi->fd,&set)) {
          vbi_hasdata(vbi);
      }
    }
    if (have_fb)
      fb_cleanup();
    tty_goto(0,0);
    tty_restore();
}

Generated by  Doxygen 1.6.0   Back to index