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

terminal.c

/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2006  Ladislav Vaiz <ok1zia@nagano.cz>
    and authors of web browser Links 0.96

    This program is free software; you can redistribute it and/or                                                        
    modify it under the terms of the GNU General Public License                                                          
    version 2 as published by the Free Software Foundation.

*/


#include "header.h"

struct terminal *term;

int hard_write(int fd, char *p, int l)
{
    if (fd<0) return -1;
    
    int w = 1;
    int t = 0;
    while (l > 0 && w) {
        if ((w = write(fd, p, l)) < 0) {
            if (errno == EINTR) continue;
            return -1;
        }
        t += w;
        p += w;
        l -= w;
    }
    return t;
}

int hard_read(int fd, char *p, int l)
{
    int r = 1;
    int t = 0;
    while (l > 0 && r) {
        if ((r = read(fd, p, l)) < 0) {
            if (errno == EINTR) continue;
            return -1;
        }
        /*{int ww;for(ww=0;ww<r;ww++)fprintf(stderr," %02x",(int)p[ww]);fflush(stderr);}*/
        t += r;
        p += r;
        l -= r;
    }
    return t;
}

char *get_cwd()
{
    int bufsize = 128;
    char *buf;
    while (1) {
        if (!(buf = mem_alloc(bufsize))) return NULL;
        if (getcwd(buf, bufsize)) return buf;
        mem_free(buf);
        if (errno == EINTR) continue;
        if (errno != ERANGE) return NULL;
        bufsize += 128;
    }
    return NULL;
}

void set_cwd(char *path)
{
    if (path) while (chdir(path) && errno == EINTR) ;
}

/*struct list_head terminals = {&terminals, &terminals};*/

void alloc_term_screen(struct terminal *term, int x, int y)
{
    unsigned *s, *t;
    if ((s = mem_realloc(term->screen, x * y * sizeof(unsigned)))) {
        if ((t = mem_realloc(term->last_screen, x * y * sizeof(unsigned)))) {
            memset(t, -1, x * y * sizeof(unsigned));
            term->x = x;
            term->y = y;
            term->last_screen = t;
            memset(s, 0, x * y * sizeof(unsigned));
            term->screen = s;
            term->dirty = 1;
        }
    }
}

void in_term(union cba_t);
void check_if_no_terminal(void);

void clear_terminal(void)
{
    if (!term) return;
    fill_area(0, 0, term->x, term->y, ' ');
    set_cursor(0, 0, 0, 0);
}

void redraw_terminal_ev(struct terminal *term, int e)
{
    struct window *win;
    struct event ev = {0, 0, 0, 0};
    
    if (!term) return;
    ev.ev = e;
    ev.x = term->x;
    ev.y = term->y;
    clear_terminal();
    term->redrawing = 2;
    foreachback(win, term->windows) win->handler(win, &ev, 0);
    term->redrawing = 0;
    
}

void redraw_terminal(union cba_t cba)
{
    /*if (!term) return;*/
    redraw_terminal_ev(term, EV_REDRAW);
}

void redraw_terminal_all(void)
{
    if (!term) return;
    redraw_terminal_ev(term, EV_RESIZE);
}

void redraw_later(void)
{
    if (!term) return;
    register_bottom_half(redraw_terminal, CBA0);
}

void erase_screen(void)
{
    if (!term) return;
    if (!term->master || !is_blocked()) {
        if (term->master) want_draw();
        hard_write(term->fdout, "\033[2J\033[1;1H", 10);
        if (term->master) done_draw();
    }
}

void redraw_terminal_cls()
{
    if (!term) return;
    erase_screen();
    alloc_term_screen(term, term->x, term->y);
    redraw_terminal_all();
}

/*void cls_redraw_all_terminals()
{
    struct terminal *term;
    foreach(term, terminals) redraw_terminal_cls(term);
} */

void redraw_from_window(struct window *win)
{
    struct terminal *term = win->term;
    struct window *end = (void *)&term->windows;
    struct event ev = {EV_REDRAW, 0, 0, 0};
    ev.x = term->x;
    ev.y = term->y;
    if (term->redrawing) return;
    term->redrawing = 1;
    for (win = win->prev; win != end; win = win->prev) {
        win->handler(win, &ev, 0);
    }
    term->redrawing = 0;
}

void redraw_below_window(struct window *win)
{
    int tr;
    struct terminal *term = win->term;
    struct window *end = win;
    struct event ev = {EV_REDRAW, 0, 0, 0};
    ev.x = term->x;
    ev.y = term->y;
    if (term->redrawing >= 2) return;
    tr = term->redrawing;
    win->term->redrawing = 2;
    for (win = term->windows.prev; win != end; win = win->prev) {
        win->handler(win, &ev, 0);
    }
    term->redrawing = tr;
}

void add_window_at_pos(void (*handler)(struct window *, struct event *, int), void *data, struct window *at)
{
    struct event ev = {EV_INIT, 0, 0, 0};
    struct window *win;
    ev.x = term->x;
    ev.y = term->y;
    if (!(win = mem_alloc(sizeof (struct window)))) {
        mem_free(data);
        return;
    }
    win->handler = handler;
    win->data = data;
    win->term = term;
    win->xp = win->yp = 0;
    add_at_pos(at, win);
    win->handler(win, &ev, 0);
}

void add_window(void (*handler)(struct window *, struct event *, int), void *data)
{
    add_window_at_pos(handler, data, (struct window *)&term->windows);
}

void delete_window(struct window *win)
{
    struct event ev = {EV_ABORT, 0, 0, 0};
    win->handler(win, &ev, 1);
    del_from_list(win);
    if (win->data) mem_free(win->data);
    redraw_terminal(CBA0);
    mem_free(win);
}

void delete_window_ev(struct window *win, struct event *ev)
{
    struct window *w = win->next;
    if ((void *)w == &win->term->windows) w = NULL;
    delete_window(win);
    if (ev && w && w->next != w) w->handler(w, ev, 1);
}

void set_window_ptr(struct window *win, int x, int y)
{
    win->xp = x;
    win->yp = y;
}

void get_parent_ptr(struct window *win, int *x, int *y)
{
    if ((void *)win->next != &win->term->windows) {
        *x = win->next->xp;
        *y = win->next->yp;
    } else {
        *x = *y = 0;
    }
}

struct window *get_root_window()
{
    if (list_empty(term->windows)) {
        internal("terminal has no windows");
        return NULL;
    }
    return (struct window *)term->windows.prev;
}

00256 struct ewd {
    void (*fn)(void *);
    void *data;
    int b;
};

void empty_window_handler(struct window *win, struct event *ev, int fwd)
{
    struct window *n;
    struct ewd *ewd = win->data;
    int x, y;
    void (*fn)(void *) = ewd->fn;
    void *data = ewd->data;
    if (ewd->b) return;
    switch (ev->ev) {
        case EV_INIT:
        case EV_RESIZE:
        case EV_REDRAW:
            get_parent_ptr(win, &x, &y);
            set_window_ptr(win, x, y);
            return;
        case EV_ABORT:
            fn(data);
            return;
    }
    ewd->b = 1;
    n = win->next;
    delete_window(win);
    fn(data);
    if (n->next != n) n->handler(n, ev, fwd);
}

/*void add_empty_window(void (*fn)(void *), void *data)
{
    struct ewd *ewd;
    if (!(ewd = mem_alloc(sizeof(struct ewd)))) return;
    ewd->fn = fn;
    ewd->data = data;
    ewd->b = 0;
    add_window(empty_window_handler, ewd);
} */

void free_term_specs()
{
    free_list(term_specs);
}

struct list_head term_specs = {&term_specs, &term_specs};

struct term_spec dumb_term = { NULL, NULL, "", 0, 0, 0, 0, 0, 0 };

struct term_spec *get_term_spec(char *term)
{
    struct term_spec *t;
    foreach(t, term_specs) if (!strcasecmp(t->term, term)) return t;
    return &dumb_term;
}

struct term_spec *new_term_spec(char *term)
{
    struct term_spec *t;
    foreach(t, term_specs) if (!strcasecmp(t->term, term)) return t;
    if (!(t = mem_alloc(sizeof(struct term_spec)))) return NULL;
    memcpy(t, &dumb_term, sizeof(struct term_spec));
    if (strlen(term) < MAX_TERM_LEN) strcpy(t->term, term);
    else memcpy(t->term, term, MAX_TERM_LEN - 1), t->term[MAX_TERM_LEN - 1] = 0;
    add_to_list(term_specs, t);
    sync_term_specs();
    return t;
}

void sync_term_specs()
{
    if (!term) return;
    term->spec = get_term_spec(term->term);
} 

struct terminal *init_term(int fdin, int fdout, 
        void (*root_window)(struct window *, struct event *, int))
{
    struct terminal *term;
    struct window *win;
    if (!(term = mem_alloc(sizeof (struct terminal)))) {
        terminate=1;
        return NULL;
    }
    memset(term, 0, sizeof(struct terminal));
    term->fdin = fdin;
    term->fdout = fdout;
    term->master = term->fdout == get_output_handle();
    /*term->x = 0;
    term->y = 0;
    term->cx = 0;
    term->cy = 0;*/
    term->lcx = -1;
    term->lcy = -1;
    term->dirty = 1;
    term->redrawing = 0;
    term->blocked = -1;
    term->screen = DUMMY;
    term->last_screen = DUMMY;
    term->spec = &dumb_term;
    term->term[0] = 0;
    term->cwd[0] = 0;
    term->input_queue = DUMMY;
    term->qlen = 0;
    init_list(term->windows);
    if (!(win = mem_alloc(sizeof (struct window)))) {
        mem_free(term);
        terminate=1;
        return NULL;
    }
    win->handler = root_window;
    win->data = NULL;
    win->term = term;
    add_to_list(term->windows, win);
    if (fdin!=-1){
        set_handlers(fdin, in_term, NULL, destroy_terminal, CBA0);
    }
    return term;
}

void term_send_event(struct terminal *term, struct event *ev)
{
      struct window *win;

/*    assert(ev && term && !list_empty(term->windows));*/
/*    if_assert_failed return;*/

      win = term->windows.next;
      win->handler(win, ev, 0);
}

static void term_send_ucs(struct terminal *term, struct event *ev, unicode_val u)
{
      char *recoded;

      recoded = u2cp(u, term->spec->charset);
      if (!recoded) recoded = "*";
      while (*recoded) {
            ev->x = *recoded;
            term_send_event(term, ev);
            recoded++;
      }
}

#define get_bool_opt(s, opt) (s->opt == 1 ? 1 : 0)

void in_term(union cba_t cba)
{
    struct event *ev;
    int r;
    char *iq, *c;
    if (!(iq = mem_realloc(term->input_queue, term->qlen + ALLOC_GR))) {
        destroy_terminal(CBA0);
        return;
    }
    term->input_queue = iq;
    if ((r = read(term->fdin, iq + term->qlen, ALLOC_GR)) <= 0) {
        if (r == -1 && errno != ECONNRESET) error("ERROR: error %d on terminal: could not read event", errno);
        destroy_terminal(CBA0);
        return;
    }
#ifdef HAVE_SDL    
    if (sdl){
        LOCK(sdl->eventpipestate);
        sdl->eventpipestate-=r;
/*        dbg("r %d\n", sdl->eventpipestate);*/
        UNLOCK(sdl->eventpipestate);
    }
#endif

    
    term->qlen += r;
    test_queue:
    if (term->qlen < sizeof(struct event)) return;
    ev = (struct event *)iq;
    
  /*  dbg("in_term [%d,%d,%d,%d]\n",ev->ev,ev->x,ev->y,ev->b);*/
/*    dbg("in_term qlen=%d\n", term->qlen);*/

    if (term->qlen > sizeof(struct event) &&    /* more than one event */
        ev->ev==EV_KBD && ev->x==KBD_TAB){       /* processing TAB keypress */
        for (c=iq+sizeof(struct event); c<iq+term->qlen;c+=sizeof(struct event)){
            ev = (struct event *)c;
            /*dbg("in_term c=%d [%d,%d,%d,%d]\n",(c-iq)/sizeof(struct event),ev->ev,ev->x,ev->y,ev->b);*/
            if (ev->ev!=EV_KBD || ev->x!=KBD_TAB) continue;
            ev->ev=EV_SKIP;
            
        }
    }
    
    
    ev = (struct event *)iq;
    
    r = sizeof(struct event);
    if (ev->ev != EV_INIT && ev->ev != EV_RESIZE && ev->ev != EV_REDRAW && ev->ev != EV_KBD && ev->ev != EV_MOUSE && ev->ev != EV_ABORT && ev->ev!=EV_SDLRESIZE && ev->ev!=EV_SKIP) {
        error("ERROR: error on terminal: bad event %d", ev->ev);
        goto mm;
    }
    if (ev->ev == EV_INIT) {
        char *ts;
        int xwin;
        
        xwin = is_xterm() * ENV_XWIN + can_twterm() * ENV_TWIN + (!!getenv("STY")) * ENV_SCREEN + get_system_env();
        if (!(ts = getenv("TERM"))) ts = "";
        strcpy(term->term, ts);
    
        if (!(ts = get_cwd()) && !(ts = stracpy(""))) goto neni_pamet;
        strcpy(term->cwd, ts);
        mem_free(ts);
        neni_pamet:;
        term->environment=xwin;
        
        sync_term_specs();
    }
    if (ev->ev == EV_SDLRESIZE){
        dbg("EV_SDLRESIZE(%d,%d) (%d,%d)\n", ev->x, ev->y, ev->mx, ev->my);
#ifdef HAVE_SDL        
        if (sdl) {
                  cfg->gfx_x=ev->mx;
                  cfg->gfx_y=ev->my;
                  sdl_setvideomode(ev->mx, ev->my, 0);
            }
#endif
        resize_terminal(CBA0);
    }
    if (ev->ev == EV_REDRAW || ev->ev == EV_RESIZE || ev->ev == EV_INIT) {
        struct window *win;
        send_redraw:
        if (ev->x < 0 || ev->y < 0) {
            error("ERROR: bad terminal size: %d, %d", (int)ev->x, (int)ev->y);
            goto mm;
        }
        alloc_term_screen(term, ev->x, ev->y);
        clear_terminal();
        erase_screen();
        term->redrawing = 1;
        foreachback(win, term->windows) win->handler(win, ev, 0);
        term->redrawing = 0;
    }
      if (ev->ev == EV_MOUSE && preferred_func(ev))
            term_send_event(term, ev);
      if (ev->ev == EV_KBD) {
            if (upcase(ev->x) == 'L' && ev->y == KBD_CTRL) {
                  ev->ev = EV_REDRAW;
                  ev->x = term->x;
                  ev->y = term->y;
                  goto send_redraw;
            } else if (ev->x == KBD_CTRL_C) 
                  ((struct window *)&term->windows)->prev->handler(term->windows.prev, ev, 0);
            else if (preferred_func(ev)) {
/*                ((struct window *)&term->windows)->next->handler(term->windows.next, ev, 0);*/
                  int utf8_io = -1;

                  if (term->utf_8.len) {
                        utf8_io = get_bool_opt(term->spec, utf_8_io);
                        if ((ev->x & 0xC0) == 0x80 && utf8_io) {
                              term->utf_8.ucs <<= 6;
                              term->utf_8.ucs |= ev->x & 0x3F;
                              if (! --term->utf_8.len) {
                                    unicode_val u = term->utf_8.ucs;
                                    if (u < term->utf_8.min)
                                          u = UCS_NO_CHAR;
                                    term_send_ucs(term, ev, u);
                              }
                              goto mm;
                        } else {
                              term->utf_8.len = 0;
                              term_send_ucs(term, ev, UCS_NO_CHAR);
                        }
                  }

                  if (ev->x < 0x80 || ev->x > 0xFF || (utf8_io == -1 ?
                        !get_bool_opt(term->spec, utf_8_io) : !utf8_io)) {
                        term_send_event(term, ev);
                        goto mm;
                  } else if ((ev->x & 0xC0) == 0xC0 && (ev->x & 0xFE) != 0xFE) {
                        register unsigned int mask, cov = 0x80;
                        int len = 0;

                        for (mask = 0x80; ev->x & mask; mask >>= 1) {
                              len++;
                              term->utf_8.min = cov;
                              cov = 1 << (1 + 5 * len);
                        }
                        term->utf_8.len = len - 1;
                        term->utf_8.ucs = ev->x & (mask - 1);
                        goto mm;
                  }
                  term_send_ucs(term, ev, UCS_NO_CHAR);
            }
    }
    if (ev->ev == EV_ABORT) destroy_terminal(CBA0);
    /*redraw_screen(term);*/
    mm:
    if (term->qlen == r) term->qlen = 0;
    else memmove(iq, iq + r, term->qlen -= r);
    goto test_queue;
}

inline int getcompcode(int c)
{
    return (c<<1 | (c&4)>>2) & 7;
}

char frame_dumb[48] =  "   ||||++||++++++--|-+||++--|-+----++++++++     ";
char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla    ";

/* For UTF8 I/O */
static char frame_vt100_u[48] = {
      177, 177, 177, 179, 180, 180, 180, 191,
      191, 180, 179, 191, 217, 217, 217, 191,
      192, 193, 194, 195, 196, 197, 195, 195,
      192, 218, 193, 194, 195, 196, 197, 193,
      193, 194, 194, 192, 192, 218, 218, 197,
      197, 217, 218, 177,  32, 32,  32,  32
};

char frame_koi[48] = {
    144,145,146,129,135,178,180,167,
    166,181,161,168,174,173,172,131,
    132,137,136,134,128,138,175,176,
    171,165,187,184,177,160,190,185,
    186,182,183,170,169,162,164,189,
    188,133,130,141,140,142,143,139,
};

char frame_restrict[48] = {
    0, 0, 0, 0, 0, 179, 186, 186,
    205, 0, 0, 0, 0, 186, 205, 0,
    0, 0, 0, 0, 0, 0, 179, 186,
    0, 0, 0, 0, 0, 0, 0, 205,
    196, 205, 196, 186, 205, 205, 186, 186,
    179, 0, 0, 0, 0, 0, 0, 0,
};

/* characters 128-159 are special for xterm unless
 * *VT100*allowC1Printable property is not set */

#define PRINT_CHAR(p)                                                       \
{                                                                           \
      unsigned ch = term->screen[p];                                          \
      unsigned char c = ch & 0xff;                                            \
      unsigned char A = ch >> 8 & 0x7f;                                       \
      int charset = s->charset;                                               \
      if (s->mode == TERM_LINUX) {                                            \
            if (s->m11_hack) {                                                  \
                  if (ch >> 15 != mode) {                                         \
                        if (!(mode = ch >> 15))                                     \
                              add_to_str(&a, &l, "\033[10m");                         \
                else                                                        \
                              add_to_str(&a, &l, "\033[11m");                             \
                  }                                                               \
            }                                                                   \
            if ((mode = ch >> 15) && c >= 176 && c < 224) {                     \
                  charset = get_cp_index("cp437");                                \
                  if (s->restrict_852 && frame_restrict[c - 176])                 \
                        c = frame_restrict[c - 176];                                \
            }                                                                   \
      } else if (s->mode == TERM_VT100) {                                     \
            if (ch >> 15 != mode) {                                             \
                  if (!(mode = ch >> 15))                                         \
                        add_to_str(&a, &l, "\x0f");                                 \
                  else                                                            \
                        add_to_str(&a, &l, "\x0e");                                 \
            }                                                                   \
            if (mode && c >= 176 && c < 224) {                                  \
                  charset = get_cp_index("cp437");                                \
                  if (get_bool_opt(s, utf_8_io)                                   \
                        && strcasecmp(term->term, "xterm"))                         \
                        c = frame_vt100_u[c - 176];                                 \
                  else                                                            \
                        c = frame_vt100[c - 176];                                   \
            }                                                                   \
      } else if (s->mode == TERM_KOI8) {                                      \
            if (ch >> 15 != mode && (mode = ch >> 15))                          \
                  charset = get_cp_index("koi8-r");                               \
            if (mode && c >= 176 && c < 224)                                    \
                  c = frame_koi[c - 176];                                         \
      } else if (s->mode == TERM_DUMB && (ch >> 15) && c >= 176 && c < 224)   \
            c = frame_dumb[c - 176];                                            \
      if (!(A & 0100) && (A >> 3) == (A & 7))                                 \
            A = (A & 070) | 7 * !(A & 020);                                     \
      if (A != attrib) {                                                      \
            attrib = A;                                                         \
            add_to_str(&a, &l, "\033[0");                                       \
            if (s->col) {                                                       \
                  char m[4];                                                      \
                  m[0] = ';'; m[1] = '3'; m[3] = 0;                               \
                  m[2] = (attrib & 7) + '0';                                      \
                  add_to_str(&a, &l, m);                                          \
                  m[1] = '4';                                                     \
                  m[2] = (attrib >> 3 & 7) + '0';                                 \
                  add_to_str(&a, &l, m);                                          \
            } else if (getcompcode(attrib & 7) < getcompcode(attrib >> 3 & 7))  \
                  add_to_str(&a, &l, ";7");                                       \
            if (attrib & 0100)                                                  \
                  add_to_str(&a, &l, ";1");                                       \
            add_to_str(&a, &l, "m");                                            \
      }                                                                       \
      if (c>=' ' && (c<127 || c>159) && c!=255) {                             \
            if (get_bool_opt(s, utf_8_io))                                      \
                  add_to_str(&a, &l, cp2utf_8(charset, c));                       \
            else                                                                \
                  add_chr_to_str(&a, &l, c);                                      \
      }                                                                       \
      else if (!c || c == 1) add_chr_to_str(&a, &l, ' ');                     \
      else add_chr_to_str(&a, &l, '.');                                       \
      cx++;                                                                   \
}                                                                           \

/*void redraw_all_terminals()
{
    struct terminal *term;
    foreach(term, terminals) redraw_screen(term);
}*/

void term_redraw_screen()
{
    int x, y, p = 0;
    int cx = -1, cy = -1;
    /*unsigned*/ char *a;
    int attrib = -1;
    int mode = -1;
    int l = 0;
    struct term_spec *s;
    if (!term->dirty || (term->master && is_blocked())) return;
    if (!(a = init_str())) return;
    s = term->spec;
    for (y = 0; y < term->y; y++)
        for (x = 0; x < term->x; x++, p++) {
            if (y == term->y - 1 && x == term->x - 1) break;
            if (term->screen[p] == term->last_screen[p]) continue;
            if ((term->screen[p] & 0x3800) == (term->last_screen[p] & 0x3800) && ((term->screen[p] & 0xff) == 0 || (term->screen[p] & 0xff) == 1 || (term->screen[p] & 0xff) == ' ') && ((term->last_screen[p] & 0xff) == 0 || (term->last_screen[p] & 0xff) == 1 || (term->last_screen[p] & 0xff) == ' ')) continue;
            if (cx == x && cy == y) goto pc;/*PRINT_CHAR(p)*/
            else if (cy == y && x - cx < 10) {
                int i;
                for (i = x - cx; i >= 0; i--) PRINT_CHAR(p - i);
            } else {
                add_to_str(&a, &l, "\033[");
                add_num_to_str(&a, &l, y + 1);
                add_to_str(&a, &l, ";");
                add_num_to_str(&a, &l, x + 1);
                add_to_str(&a, &l, "H");
                cx = x; cy = y;
                pc:
                PRINT_CHAR(p);
            }
        }
    if (l) {
        if (s->col) add_to_str(&a, &l, "\033[37;40m");
        add_to_str(&a, &l, "\033[0m");
        if (s->mode == TERM_LINUX && s->m11_hack) add_to_str(&a, &l, "\033[10m");
        if (s->mode == TERM_VT100) add_to_str(&a, &l, "\x0f");
    }
    if (l || term->cx != term->lcx || term->cy != term->lcy) {
        term->lcx = term->cx;
        term->lcy = term->cy;
        add_to_str(&a, &l, "\033[");
        add_num_to_str(&a, &l, term->cy + 1);
        add_to_str(&a, &l, ";");
        add_num_to_str(&a, &l, term->cx + 1);
        add_to_str(&a, &l, "H");
    }
    if (l && term->master) want_draw();
    hard_write(term->fdout, a, l);
    if (l && term->master) done_draw();
      
    mem_free(a);
    memcpy(term->last_screen, term->screen, term->x * term->y * sizeof(int));
    term->dirty = 0;
}

void destroy_terminal(union cba_t cba)
{
    if (!term) return;
    terminate=1;
    while ((term->windows.next) != &term->windows) delete_window(term->windows.next);
    /*if (term->cwd) mem_free(term->cwd);*/
    if (term->title) mem_free(term->title);
    mem_free(term->screen);
    term->screen=NULL;
    mem_free(term->last_screen);
    term->screen=NULL;
    set_handlers(term->fdin, NULL, NULL, NULL, CBA0);
    mem_free(term->input_queue);
    if (term->blocked != -1) {
        close(term->blocked);
        set_handlers(term->blocked, NULL, NULL, NULL, CBA0);
    }
    close(term->fdin);
    if (term->fdout != 1) {
        if (term->fdout != term->fdin) close(term->fdout);
    } else {
        unhandle_terminal_signals();
        free_all_itrms();
/*#ifndef NO_FORK_ON_EXIT
        if (!list_empty(terminals)) {
            if (fork()) exit(0);
        }
#endif */
    }
    mem_free(term);
    term=NULL;
}

/*void destroy_all_terminals()
{
    struct terminal *term;
    while ((void *)(term = terminals.next) != &terminals) destroy_terminal(term);
}

void check_if_no_terminal(void)
{
    if (!list_empty(terminals)) return;
    terminate = 1;
} */

void set_char(int x, int y, unsigned c)
{
    term->dirty = 1;
    if (x >= 0 && x < term->x && y >= 0 && y < term->y) term->screen[x + term->x * y] = c;
}

unsigned get_char(int x, int y)
{
    if (x >= term->x) x = term->x - 1;
    if (x < 0) x = 0;
    if (y >= term->y) y = term->y - 1;
    if (y < 0) y = 0;
    return term->screen[x + term->x * y];
}

void set_color(int x, int y, unsigned c)
{
    term->dirty = 1;
    if (x >= 0 && x < term->x && y >= 0 && y < term->y) term->screen[x + term->x * y] = (term->screen[x + term->x * y] & 0x80ff) | (c & ~0x80ff);
}

void set_only_char(int x, int y, unsigned c)
{
    term->dirty = 1;
    if (x >= 0 && x < term->x && y >= 0 && y < term->y) term->screen[x + term->x * y] = (term->screen[x + term->x * y] & ~0x80ff) | (c & 0x80ff);
}

void set_line(int x, int y, int l, chr *line)
{
    int i;
    term->dirty = 1;
    for (i = x >= 0 ? 0 : -x; i < (x+l <= term->x ? l : term->x-x); i++)
        term->screen[x+i + term->x * y] = line[i];
}

void set_line_color(int x, int y, int l, unsigned c)
{
    int i;
    term->dirty = 1;
    for (i = x >= 0 ? 0 : -x; i < (x+l <= term->x ? l : term->x-x); i++)
        term->screen[x+i + term->x * y] = (term->screen[x+i + term->x * y] & 0x80ff) | (c & ~0x80ff);
}

void fill_area(int x, int y, int xw, int yw, unsigned c)
{
    int i,j;
    term->dirty = 1;
    for (j = y >= 0 ? 0 : -y; j < yw && y+j < term->y; j++)
        for (i = x >= 0 ? 0 : -x; i < xw && x+i < term->x; i++) 
            term->screen[x+i + term->x*(y+j)] = c;
}

void fill_lastarea(int x, int y, int xw, int yw, unsigned c)
{
    int i,j;
    for (j = y >= 0 ? 0 : -y; j < yw && y+j < term->y; j++)
        for (i = x >= 0 ? 0 : -x; i < xw && x+i < term->x; i++) 
            term->last_screen[x+i + term->x*(y+j)] = c;
}

int p1[] = { 218, 191, 192, 217, 179, 196 };
int p2[] = { 201, 187, 200, 188, 186, 205 };

void draw_frame(int x, int y, int xw, int yw, unsigned c, int w)
{
    int *p = w > 1 ? p2 : p1;
    c |= ATTR_FRAME;
    set_char(x, y, c+p[0]);
    set_char(x+xw-1, y, c+p[1]);
    set_char(x, y+yw-1, c+p[2]);
    set_char(x+xw-1, y+yw-1, c+p[3]);
    fill_area(x, y+1, 1, yw-2, c+p[4]);
    fill_area(x+xw-1, y+1, 1, yw-2, c+p[4]);
    fill_area(x+1, y, xw-2, 1, c+p[5]);
    fill_area(x+1, y+yw-1, xw-2, 1, c+p[5]);
}

void print_text(int x, int y, int l, char *text, unsigned c)
{
    for (; l-- && *text; text++, x++) set_char(x, y,((unsigned char)*text) + c);
}

void set_cursor(int x, int y, int altx, int alty)
{
    term->dirty = 1;
    if (term->spec->block_cursor) x = altx, y = alty;
    if (x >= term->x) x = term->x - 1;
    if (y >= term->y) y = term->y - 1;
    if (x < 0) x = 0;
    if (y < 0) y = 0;
    term->cx = x;
    term->cy = y;
}

void exec_thread(char *path, int p)
{
#if defined(HAVE_SETPGID) && !defined(BEOS) && !defined(HAVE_BEGINTHREAD)
    if (path[0] == 2) setpgid(0, 0);
#endif
    exe(path + 1);
    close(p);
    if (path[1 + strlen(path + 1) + 1]) unlink(path + 1 + strlen(path + 1) + 1);
}

void close_handle(union cba_t cba)
{
    int h = cba.int_;
    close(h);
    set_handlers(h, NULL, NULL, NULL, CBA0);
}

void unblock_terminal(union cba_t cba)
{
    close_handle((union cba_t)term->blocked);
    term->blocked = -1;
    set_handlers(term->fdin, in_term, NULL, destroy_terminal, CBA0);
    unblock_itrm(term->fdin);
    redraw_terminal_cls();
}

void exec_on_terminal(char *path, char *delete, int fg)
{
    if (path && !*path) return;
    if (!path) path="";
#ifdef NO_FG_EXEC
    fg = 0;
#endif
    if (term->master) {
        if (!*path) dispatch_special(delete);
        else {
            int blockh;
            char *param;
            if (is_blocked() && fg) {
                unlink(delete);
                return;
            }
            if (!(param = mem_alloc(strlen(path) + strlen(delete) + 3))) return;
            param[0] = fg;
            strcpy(param + 1, path);
            strcpy(param + 1 + strlen(path) + 1, delete);
            if (fg == 1) block_itrm(term->fdin);
            if ((blockh = start_thread((void (*)(void *, int))exec_thread, param, strlen(path) + strlen(delete) + 3)) == -1) {
                if (fg == 1) unblock_itrm(term->fdin);
                mem_free(param);
                return;
            }
            mem_free(param);
            if (fg == 1) {
                term->blocked = blockh;
                set_handlers(blockh, unblock_terminal, NULL, unblock_terminal, CBA0);
                set_handlers(term->fdin, NULL, NULL, destroy_terminal, CBA0);
                /*block_itrm(term->fdin);*/
            } else {
                set_handlers(blockh, close_handle, NULL, close_handle, (union cba_t)blockh);
            }
        }
    } else {
        char *data;
        if ((data = mem_alloc(strlen(path) + strlen(delete) + 4))) {
            data[0] = 0;
            data[1] = fg;
            strcpy(data + 2, path);
            strcpy(data + 3 + strlen(path), delete);
            hard_write(term->fdout, data, strlen(path) + strlen(delete) + 4);
            mem_free(data);
        }
        /*char x = 0;
        hard_write(term->fdout, &x, 1);
        x = fg;
        hard_write(term->fdout, &x, 1);
        hard_write(term->fdout, path, strlen(path) + 1);
        hard_write(term->fdout, delete, strlen(delete) + 1);*/
    }
}

void do_terminal_function(char code, char *data)
{
    char *x_data;
    if (!(x_data = mem_alloc(strlen(data) + 2))) return;
    x_data[0] = code;
    strcpy(x_data + 1, data);
    exec_on_terminal(NULL, x_data, 0);
    mem_free(x_data);
}

void set_terminal_title(char *title)
{
    if (term->title && !strcmp(title, term->title)) return;
    if (term->title) mem_free(term->title);
    term->title = stracpy(title);
#ifdef HAVE_SDL    
    if (!sdl) 
#endif
        do_terminal_function(TERM_FN_TITLE, title);
}
    

void set_ctest_title(){
    gchar *c;

    if (ctest){
        c = g_strdup_printf(" %s %s - %s %s", ctest->pcall, ctest->tname, PACKAGE_NAME, PACKAGE_VERSION);
        set_terminal_title(c);
        g_free(c);
    }else{
        c = g_strdup_printf(" %s %s", PACKAGE_NAME, PACKAGE_VERSION);
        set_terminal_title(c);
        g_free(c);
    }
}

Generated by  Doxygen 1.6.0   Back to index