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

display.c

/* $Id: display.c,v 1.68 2003/09/26 17:59:51 ukai Exp $ */
#include <signal.h>
#include "fm.h"

#define MAX(a, b)  ((a) > (b) ? (a) : (b))
#define MIN(a, b)  ((a) < (b) ? (a) : (b))

/* *INDENT-OFF* */
#ifdef USE_COLOR

#define EFFECT_ANCHOR_START       effect_anchor_start()
#define EFFECT_ANCHOR_END         effect_anchor_end()
#define EFFECT_IMAGE_START        effect_image_start()
#define EFFECT_IMAGE_END          effect_image_end()
#define EFFECT_FORM_START         effect_form_start()
#define EFFECT_FORM_END           effect_form_end()
#define EFFECT_ACTIVE_START     effect_active_start()
#define EFFECT_ACTIVE_END       effect_active_end()
#define EFFECT_VISITED_START      effect_visited_start()
#define EFFECT_VISITED_END        effect_visited_end()
#define EFFECT_MARK_START         effect_mark_start()
#define EFFECT_MARK_END           effect_mark_end()

/*-
 * color: 
 *     0  black 
 *     1  red 
 *     2  green 
 *     3  yellow
 *     4  blue 
 *     5  magenta 
 *     6  cyan 
 *     7  white 
 */

#define EFFECT_ANCHOR_START_C       setfcolor(anchor_color)
#define EFFECT_IMAGE_START_C        setfcolor(image_color)
#define EFFECT_FORM_START_C         setfcolor(form_color)
#define EFFECT_ACTIVE_START_C      (setfcolor(active_color), underline())
#define EFFECT_VISITED_START_C      setfcolor(visited_color)
#ifdef USE_BG_COLOR
#define EFFECT_MARK_START_C         setbcolor(mark_color)
#else
#define EFFECT_MARK_START_C         standout()
#endif

#define EFFECT_IMAGE_END_C          setfcolor(basic_color)
#define EFFECT_ANCHOR_END_C         setfcolor(basic_color)
#define EFFECT_FORM_END_C           setfcolor(basic_color)
#define EFFECT_ACTIVE_END_C        (setfcolor(basic_color), underlineend())
#define EFFECT_VISITED_END_C        setfcolor(basic_color)
#ifdef USE_BG_COLOR
#define EFFECT_MARK_END_C           setbcolor(bg_color)
#else
#define EFFECT_MARK_END_C           standend()
#endif

#define EFFECT_ANCHOR_START_M       underline()
#define EFFECT_ANCHOR_END_M         underlineend()
#define EFFECT_IMAGE_START_M        standout()
#define EFFECT_IMAGE_END_M          standend()
#define EFFECT_FORM_START_M         standout()
#define EFFECT_FORM_END_M           standend()
#define EFFECT_ACTIVE_START_NC      underline()
#define EFFECT_ACTIVE_END_NC        underlineend()
#define EFFECT_ACTIVE_START_M       bold()
#define EFFECT_ACTIVE_END_M         boldend()
#define EFFECT_VISITED_START_M /**/
#define EFFECT_VISITED_END_M /**/
#define EFFECT_MARK_START_M         standout()
#define EFFECT_MARK_END_M           standend()
#define define_effect(name_start,name_end,color_start,color_end,mono_start,mono_end) \
static void name_start { if (useColor) { color_start; } else { mono_start; }}\
static void name_end { if (useColor) { color_end; } else { mono_end; }}

define_effect(EFFECT_ANCHOR_START, EFFECT_ANCHOR_END, EFFECT_ANCHOR_START_C,
            EFFECT_ANCHOR_END_C, EFFECT_ANCHOR_START_M, EFFECT_ANCHOR_END_M)
define_effect(EFFECT_IMAGE_START, EFFECT_IMAGE_END, EFFECT_IMAGE_START_C,
            EFFECT_IMAGE_END_C, EFFECT_IMAGE_START_M, EFFECT_IMAGE_END_M)
define_effect(EFFECT_FORM_START, EFFECT_FORM_END, EFFECT_FORM_START_C,
            EFFECT_FORM_END_C, EFFECT_FORM_START_M, EFFECT_FORM_END_M)
define_effect(EFFECT_MARK_START, EFFECT_MARK_END, EFFECT_MARK_START_C,
            EFFECT_MARK_END_C, EFFECT_MARK_START_M, EFFECT_MARK_END_M)

/*****************/
static void
EFFECT_ACTIVE_START
{
    if (useColor) {
      if (useActiveColor) {
#ifdef __EMX__
          if(!getenv("WINDOWID"))
            setfcolor(active_color);
          else
#endif
          {
            EFFECT_ACTIVE_START_C;
          }
      } else {
          EFFECT_ACTIVE_START_NC;
      }
    } else {
      EFFECT_ACTIVE_START_M;
    }
}

static void
EFFECT_ACTIVE_END
{
    if (useColor) {
      if (useActiveColor) {
          EFFECT_ACTIVE_END_C;
      } else {
          EFFECT_ACTIVE_END_NC;
      }
    } else {
      EFFECT_ACTIVE_END_M;
    }
}

static void
EFFECT_VISITED_START
{
    if (useVisitedColor) {
      if (useColor) {
          EFFECT_VISITED_START_C;
      } else {
          EFFECT_VISITED_START_M;
      }
    }
}

static void
EFFECT_VISITED_END
{
    if (useVisitedColor) {
      if (useColor) {
          EFFECT_VISITED_END_C;
      } else {
          EFFECT_VISITED_END_M;
      }
    }
}

#else                   /* not USE_COLOR */

#define EFFECT_ANCHOR_START       underline()
#define EFFECT_ANCHOR_END         underlineend()
#define EFFECT_IMAGE_START        standout()
#define EFFECT_IMAGE_END          standend()
#define EFFECT_FORM_START         standout()
#define EFFECT_FORM_END           standend()
#define EFFECT_ACTIVE_START       bold()
#define EFFECT_ACTIVE_END         boldend()
#define EFFECT_VISITED_START /**/
#define EFFECT_VISITED_END /**/
#define EFFECT_MARK_START         standout()
#define EFFECT_MARK_END           standend()
#endif                        /* not USE_COLOR */
/* *INDENT-ON* */

void
fmTerm(void)
{
    if (fmInitialized) {
      move(LASTLINE, 0);
      clrtoeolx();
      refresh();
#ifdef USE_IMAGE
      if (activeImage)
          loadImage(NULL, IMG_FLAG_STOP);
#endif
#ifdef USE_MOUSE
      if (use_mouse)
          mouse_end();
#endif                        /* USE_MOUSE */
      reset_tty();
      fmInitialized = FALSE;
    }
}


/* 
 * Initialize routine.
 */
void
fmInit(void)
{
    if (!fmInitialized) {
      initscr();
      term_raw();
      term_noecho();
#ifdef USE_IMAGE
      if (displayImage)
          initImage();
#endif
    }
    fmInitialized = TRUE;
}

/* 
 * Display some lines.
 */
static Line *cline = NULL;
static int ccolumn = -1;

static int ulmode = 0, somode = 0, bomode = 0;
static int anch_mode = 0, emph_mode = 0, imag_mode = 0, form_mode = 0,
    active_mode = 0, visited_mode = 0, mark_mode = 0, graph_mode = 0;
#ifdef USE_ANSI_COLOR
static Linecolor color_mode = 0;
#endif

#ifdef USE_BUFINFO
static Buffer *save_current_buf = NULL;
#endif

static char *delayed_msg = NULL;

static void drawAnchorCursor(Buffer *buf);
#define redrawBuffer(buf) redrawNLine(buf, LASTLINE)
static void redrawNLine(Buffer *buf, int n);
static Line *redrawLine(Buffer *buf, Line *l, int i);
#ifdef USE_IMAGE
static int image_touch = 0;
static int draw_image_flag = FALSE;
static Line *redrawLineImage(Buffer *buf, Line *l, int i);
#endif
static int redrawLineRegion(Buffer *buf, Line *l, int i, int bpos, int epos);
static void do_effects(Lineprop m);
#ifdef USE_ANSI_COLOR
static void do_color(Linecolor c);
#endif

static Str
make_lastline_link(Buffer *buf, char *title, char *url)
{
    Str s = NULL, u;
#ifdef USE_M17N
    Lineprop *pr;
#endif
    ParsedURL pu;
    char *p;
    int l = COLS - 1, i;

    if (title && *title) {
      s = Strnew_m_charp("[", title, "]", NULL);
      for (p = s->ptr; *p; p++) {
          if (IS_CNTRL(*p) || IS_SPACE(*p))
            *p = ' ';
      }
      if (url)
          Strcat_charp(s, " ");
      l -= get_Str_strwidth(s);
      if (l <= 0)
          return s;
    }
    if (!url)
      return s;
    parseURL2(url, &pu, baseURL(buf));
    u = parsedURL2Str(&pu);
    if (DecodeURL)
      u = Strnew_charp(url_unquote_conv(u->ptr, buf->document_charset));
#ifdef USE_M17N
    u = checkType(u, &pr, NULL);
#endif
    if (l <= 4 || l >= get_Str_strwidth(u)) {
      if (!s)
          return u;
      Strcat(s, u);
      return s;
    }
    if (!s)
      s = Strnew_size(COLS);
    i = (l - 2) / 2;
#ifdef USE_M17N
    while (i && pr[i] & PC_WCHAR2)
      i--;
#endif
    Strcat_charp_n(s, u->ptr, i);
    Strcat_charp(s, "..");
    i = get_Str_strwidth(u) - (COLS - 1 - get_Str_strwidth(s));
#ifdef USE_M17N
    while (i < u->length && pr[i] & PC_WCHAR2)
      i++;
#endif
    Strcat_charp(s, &u->ptr[i]);
    return s;
}

static Str
make_lastline_message(Buffer *buf)
{
    Str msg, s = NULL;
    int sl = 0;

    if (displayLink) {
#ifdef USE_IMAGE
      MapArea *a = retrieveCurrentMapArea(buf);
      if (a)
          s = make_lastline_link(buf, a->alt, a->url);
      else
#endif
      {
          Anchor *a = retrieveCurrentAnchor(buf);
          char *p = NULL;
          if (a && a->title && *a->title)
            p = a->title;
          else {
            Anchor *a_img = retrieveCurrentImg(buf);
            if (a_img && a_img->title && *a_img->title)
                p = a_img->title;
          }
          if (p || a)
            s = make_lastline_link(buf, p, a ? a->url : NULL);
      }
      if (s) {
          sl = get_Str_strwidth(s);
          if (sl >= COLS - 3)
            return s;
      }
    }

#ifdef USE_MOUSE
    if (use_mouse && mouse_action.lastline_str)
      msg = Strnew_charp(mouse_action.lastline_str);
    else
#endif                        /* not USE_MOUSE */
      msg = Strnew();
    if (displayLineInfo && buf->currentLine != NULL && buf->lastLine != NULL) {
      int cl = buf->currentLine->real_linenumber;
      int ll = buf->lastLine->real_linenumber;
      int r = (int)((double)cl * 100.0 / (double)(ll ? ll : 1) + 0.5);
      Strcat(msg, Sprintf("%d/%d (%d%%)", cl, ll, r));
    }
    else
      /* FIXME: gettextize? */
      Strcat_charp(msg, "Viewing");
#ifdef USE_SSL
    if (buf->ssl_certificate)
      Strcat_charp(msg, "[SSL]");
#endif
    Strcat_charp(msg, " <");
    Strcat_charp(msg, buf->buffername);

    if (s) {
      int l = COLS - 3 - sl;
      if (get_Str_strwidth(msg) > l) {
#ifdef USE_M17N
          char *p;
          for (p = msg->ptr; *p; p += get_mclen(p)) {
            l -= get_mcwidth(p);
            if (l < 0)
                break;
          }
          l = p - msg->ptr;
#endif
          Strtruncate(msg, l);
      }
      Strcat_charp(msg, "> ");
      Strcat(msg, s);
    }
    else {
      Strcat_charp(msg, ">");
    }
    return msg;
}

void
displayBuffer(Buffer *buf, int mode)
{
    Str msg;
    int ny = 0;

    if (!buf)
      return;
    if (buf->topLine == NULL && readBufferCache(buf) == 0) {      /* clear_buffer */
      mode = B_FORCE_REDRAW;
    }

    if (buf->width == 0)
      buf->width = INIT_BUFFER_WIDTH;
    if (buf->height == 0)
      buf->height = LASTLINE + 1;
    if ((buf->width != INIT_BUFFER_WIDTH &&
       ((buf->type && !strcmp(buf->type, "text/html")) || FoldLine))
      || buf->need_reshape) {
      buf->need_reshape = TRUE;
      reshapeBuffer(buf);
    }
    if (showLineNum) {
      if (buf->lastLine && buf->lastLine->real_linenumber > 0)
          buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
                         / log(10)) + 2;
      if (buf->rootX < 5)
          buf->rootX = 5;
      if (buf->rootX > COLS)
          buf->rootX = COLS;
    }
    else
      buf->rootX = 0;
    buf->COLS = COLS - buf->rootX;
    if (nTab > 1
#ifdef USE_MOUSE
      || mouse_action.menu_str
#endif
      ) {
      if (mode == B_FORCE_REDRAW || mode == B_REDRAW_IMAGE)
          calcTabPos();
      ny = LastTab->y + 2;
      if (ny > LASTLINE)
          ny = LASTLINE;
    }
    if (buf->rootY != ny || buf->LINES != LASTLINE - ny) {
      buf->rootY = ny;
      buf->LINES = LASTLINE - ny;
      arrangeCursor(buf);
      mode = B_REDRAW_IMAGE;
    }
    if (mode == B_FORCE_REDRAW || mode == B_SCROLL || mode == B_REDRAW_IMAGE ||
      cline != buf->topLine || ccolumn != buf->currentColumn) {
#ifdef USE_RAW_SCROLL
      if (
#ifdef USE_IMAGE
             !(activeImage && displayImage && draw_image_flag) &&
#endif
             mode == B_SCROLL && cline && buf->currentColumn == ccolumn) {
          int n = buf->topLine->linenumber - cline->linenumber;
          if (n > 0 && n < buf->LINES) {
            move(LASTLINE, 0);
            clrtoeolx();
            refresh();
            scroll(n);
          }
          else if (n < 0 && n > -buf->LINES) {
#if defined(__CYGWIN__) && LANG == JA
            move(LASTLINE + n + 1, 0);
            clrtoeolx();
            refresh();
#endif                        /* defined(__CYGWIN__) && LANG == JA */
            rscroll(-n);
          }
          redrawNLine(buf, n);
      }
      else
#endif
      {
#ifdef USE_IMAGE
          if (activeImage &&
            (mode == B_REDRAW_IMAGE ||
             cline != buf->topLine || ccolumn != buf->currentColumn)) {
            if (draw_image_flag)
                clear();
            clearImage();
            loadImage(buf, IMG_FLAG_STOP);
            image_touch++;
            draw_image_flag = FALSE;
          }
#endif
          redrawBuffer(buf);
      }
      cline = buf->topLine;
      ccolumn = buf->currentColumn;
    }
    if (buf->topLine == NULL)
      buf->topLine = buf->firstLine;

#ifdef USE_IMAGE
    if (buf->need_reshape) {
      displayBuffer(buf, B_FORCE_REDRAW);
      return;
    }
#endif

    drawAnchorCursor(buf);

    msg = make_lastline_message(buf);
    if (buf->firstLine == NULL) {
      /* FIXME: gettextize? */
      Strcat_charp(msg, "\tNo Line");
    }
    if (delayed_msg != NULL) {
      disp_message(delayed_msg, FALSE);
      delayed_msg = NULL;
      refresh();
    }
    standout();
    message(msg->ptr, buf->cursorX + buf->rootX, buf->cursorY + buf->rootY);
    standend();
    term_title(conv_to_system(buf->buffername));
    refresh();
#ifdef USE_IMAGE
    if (activeImage && displayImage && buf->img) {
      drawImage();
    }
#endif
#ifdef USE_BUFINFO
    if (buf != save_current_buf) {
      saveBufferInfo();
      save_current_buf = buf;
    }
#endif
}

static void
drawAnchorCursor0(Buffer *buf, AnchorList *al, int hseq, int prevhseq,
              int tline, int eline, int active)
{
    int i, j;
    Line *l;
    Anchor *an;

    l = buf->topLine;
    for (j = 0; j < al->nanchor; j++) {
      an = &al->anchors[j];
      if (an->start.line < tline)
          continue;
      if (an->start.line >= eline)
          return;
      for (;; l = l->next) {
          if (l == NULL)
            return;
          if (l->linenumber == an->start.line)
            break;
      }
      if (hseq >= 0 && an->hseq == hseq) {
          for (i = an->start.pos; i < an->end.pos; i++) {
            if (l->propBuf[i] & (PE_IMAGE | PE_ANCHOR | PE_FORM)) {
                if (active)
                  l->propBuf[i] |= PE_ACTIVE;
                else
                  l->propBuf[i] &= ~PE_ACTIVE;
            }
          }
          if (active)
            redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
                         an->start.pos, an->end.pos);
      }
      else if (prevhseq >= 0 && an->hseq == prevhseq) {
          if (active)
            redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
                         an->start.pos, an->end.pos);
      }
    }
}

static void
drawAnchorCursor(Buffer *buf)
{
    Anchor *an;
    int hseq, prevhseq;
    int tline, eline;

    if (!buf->firstLine || !buf->hmarklist)
      return;
    if (!buf->href && !buf->formitem)
      return;

    an = retrieveCurrentAnchor(buf);
    if (!an)
      an = retrieveCurrentMap(buf);
    if (an)
      hseq = an->hseq;
    else
      hseq = -1;
    tline = buf->topLine->linenumber;
    eline = tline + buf->LINES;
    prevhseq = buf->hmarklist->prevhseq;

    if (buf->href) {
      drawAnchorCursor0(buf, buf->href, hseq, prevhseq, tline, eline, 1);
      drawAnchorCursor0(buf, buf->href, hseq, -1, tline, eline, 0);
    }
    if (buf->formitem) {
      drawAnchorCursor0(buf, buf->formitem, hseq, prevhseq, tline, eline, 1);
      drawAnchorCursor0(buf, buf->formitem, hseq, -1, tline, eline, 0);
    }
    buf->hmarklist->prevhseq = hseq;
}

static void
redrawNLine(Buffer *buf, int n)
{
    Line *l;
    int i;

#ifdef USE_COLOR
    if (useColor) {
      EFFECT_ANCHOR_END_C;
#ifdef USE_BG_COLOR
      setbcolor(bg_color);
#endif                        /* USE_BG_COLOR */
    }
#endif                        /* USE_COLOR */
    if (nTab > 1
#ifdef USE_MOUSE
      || mouse_action.menu_str
#endif
      ) {
      TabBuffer *t;
      int l;

      move(0, 0);
#ifdef USE_MOUSE
      if (mouse_action.menu_str)
          addstr(mouse_action.menu_str);
#endif
      clrtoeolx();
      for (t = FirstTab; t; t = t->nextTab) {
          move(t->y, t->x1);
          if (t == CurrentTab)
            bold();
          addch('[');
          l = t->x2 - t->x1 - 1 - get_strwidth(t->currentBuffer->buffername);
          if (l < 0)
            l = 0;
          if (l / 2 > 0)
            addnstr_sup(" ", l / 2);
          if (t == CurrentTab)
            EFFECT_ACTIVE_START;
          addnstr(t->currentBuffer->buffername, t->x2 - t->x1 - l);
          if (t == CurrentTab)
            EFFECT_ACTIVE_END;
          if ((l + 1) / 2 > 0)
            addnstr_sup(" ", (l + 1) / 2);
          move(t->y, t->x2);
          addch(']');
          if (t == CurrentTab)
            boldend();
      }
#if 0
      move(0, COLS - 2);
      addstr(" x");
#endif
      move(LastTab->y + 1, 0);
      for (i = 0; i < COLS; i++)
          addch('~');
    }
    for (i = 0, l = buf->topLine; i < buf->LINES; i++, l = l->next) {
      if (i >= buf->LINES - n || i < -n)
          l = redrawLine(buf, l, i + buf->rootY);
      if (l == NULL)
          break;
    }
    if (n > 0) {
      move(i + buf->rootY, 0);
      clrtobotx();
    }

#ifdef USE_IMAGE
    if (!(activeImage && displayImage && buf->img))
      return;
    move(buf->cursorY + buf->rootY, buf->cursorX + buf->rootX);
    for (i = 0, l = buf->topLine; i < buf->LINES && l; i++, l = l->next) {
      if (i >= buf->LINES - n || i < -n)
          redrawLineImage(buf, l, i + buf->rootY);
    }
    getAllImage(buf);
#endif
}

static Line *
redrawLine(Buffer *buf, Line *l, int i)
{
    int j, pos, rcol, ncol, delta = 1;
    int column = buf->currentColumn;
    char *p;
    Lineprop *pr;
#ifdef USE_ANSI_COLOR
    Linecolor *pc;
#endif
#ifdef USE_COLOR
    Anchor *a;
    ParsedURL url;
    int k, vpos = -1;
#endif

    if (l == NULL) {
      if (buf->pagerSource) {
          l = getNextPage(buf, buf->LINES + buf->rootY - i);
          if (l == NULL)
            return NULL;
      }
      else
          return NULL;
    }
    move(i, 0);
    if (showLineNum) {
      char tmp[16];
      if (!buf->rootX) {
          if (buf->lastLine->real_linenumber > 0)
            buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
                           / log(10)) + 2;
          if (buf->rootX < 5)
            buf->rootX = 5;
          if (buf->rootX > COLS)
            buf->rootX = COLS;
          buf->COLS = COLS - buf->rootX;
      }
      if (l->real_linenumber && !l->bpos)
          sprintf(tmp, "%*ld:", buf->rootX - 1, l->real_linenumber);
      else
          sprintf(tmp, "%*s ", buf->rootX - 1, "");
      addstr(tmp);
    }
    move(i, buf->rootX);
    if (l->width < 0)
      l->width = COLPOS(l, l->len);
    if (l->len == 0 || l->width - 1 < column) {
      clrtoeolx();
      return l;
    }
    /* need_clrtoeol(); */
    pos = columnPos(l, column);
    p = &(l->lineBuf[pos]);
    pr = &(l->propBuf[pos]);
#ifdef USE_ANSI_COLOR
    if (useColor && l->colorBuf)
      pc = &(l->colorBuf[pos]);
    else
      pc = NULL;
#endif
    rcol = COLPOS(l, pos);

    for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
#ifdef USE_COLOR
      if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
          a = retrieveAnchor(buf->href, l->linenumber, pos + j);
          if (a) {
            parseURL2(a->url, &url, baseURL(buf));
            if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
                for (k = a->start.pos; k < a->end.pos; k++)
                  pr[k - pos] |= PE_VISITED;
            }
            vpos = a->end.pos;
          }
      }
#endif
#ifdef USE_M17N
      delta = wtf_len((wc_uchar *) & p[j]);
#endif
      ncol = COLPOS(l, pos + j + delta);
      if (ncol - column > buf->COLS)
          break;
#ifdef USE_ANSI_COLOR
      if (pc)
          do_color(pc[j]);
#endif
      if (rcol < column) {
          for (rcol = column; rcol < ncol; rcol++)
            addChar(' ', 0);
          continue;
      }
      if (p[j] == '\t') {
          for (; rcol < ncol; rcol++)
            addChar(' ', 0);
      }
      else {
#ifdef USE_M17N
          addMChar(&p[j], pr[j], delta);
#else
          addChar(p[j], pr[j]);
#endif
      }
      rcol = ncol;
    }
    if (somode) {
      somode = FALSE;
      standend();
    }
    if (ulmode) {
      ulmode = FALSE;
      underlineend();
    }
    if (bomode) {
      bomode = FALSE;
      boldend();
    }
    if (emph_mode) {
      emph_mode = FALSE;
      boldend();
    }

    if (anch_mode) {
      anch_mode = FALSE;
      EFFECT_ANCHOR_END;
    }
    if (imag_mode) {
      imag_mode = FALSE;
      EFFECT_IMAGE_END;
    }
    if (form_mode) {
      form_mode = FALSE;
      EFFECT_FORM_END;
    }
    if (visited_mode) {
      visited_mode = FALSE;
      EFFECT_VISITED_END;
    }
    if (active_mode) {
      active_mode = FALSE;
      EFFECT_ACTIVE_END;
    }
    if (mark_mode) {
      mark_mode = FALSE;
      EFFECT_MARK_END;
    }
    if (graph_mode) {
      graph_mode = FALSE;
      graphend();
    }
#ifdef USE_ANSI_COLOR
    if (color_mode)
      do_color(0);
#endif
    if (rcol - column < buf->COLS)
      clrtoeolx();
    return l;
}

#ifdef USE_IMAGE
static Line *
redrawLineImage(Buffer *buf, Line *l, int i)
{
    int j, pos, rcol;
    int column = buf->currentColumn;
    Anchor *a;
    int x, y, sx, sy, w, h;

    if (l == NULL)
      return NULL;
    if (l->width < 0)
      l->width = COLPOS(l, l->len);
    if (l->len == 0 || l->width - 1 < column)
      return l;
    pos = columnPos(l, column);
    rcol = COLPOS(l, pos);
    for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j++) {
      if (rcol - column < 0) {
          rcol = COLPOS(l, pos + j + 1);
          continue;
      }
      a = retrieveAnchor(buf->img, l->linenumber, pos + j);
      if (a && a->image && a->image->touch < image_touch) {
          Image *image = a->image;
          ImageCache *cache;

          cache = image->cache = getImage(image, baseURL(buf),
                                  buf->image_flag);
          if (cache) {
            if ((image->width < 0 && cache->width > 0) ||
                (image->height < 0 && cache->height > 0)) {
                image->width = cache->width;
                image->height = cache->height;
                buf->need_reshape = TRUE;
            }
            x = (int)((rcol - column + buf->rootX) * pixel_per_char);
            y = (int)(i * pixel_per_line);
            sx = (int)((rcol - COLPOS(l, a->start.pos)) * pixel_per_char);
            sy = (int)((l->linenumber - image->y) * pixel_per_line);
            if (sx == 0 && x + image->xoffset >= 0)
                x += image->xoffset;
            else
                sx -= image->xoffset;
            if (sy == 0 && y + image->yoffset >= 0)
                y += image->yoffset;
            else
                sy -= image->yoffset;
            if (image->width > 0)
                w = image->width - sx;
            else
                w = (int)(8 * pixel_per_char - sx);
            if (image->height > 0)
                h = image->height - sy;
            else
                h = (int)(pixel_per_line - sy);
            if (w > (int)((buf->rootX + buf->COLS) * pixel_per_char - x))
                w = (int)((buf->rootX + buf->COLS) * pixel_per_char - x);
            if (h > (int)(LASTLINE * pixel_per_line - y))
                h = (int)(LASTLINE * pixel_per_line - y);
            addImage(cache, x, y, sx, sy, w, h);
            image->touch = image_touch;
            draw_image_flag = TRUE;
          }
      }
      rcol = COLPOS(l, pos + j + 1);
    }
    return l;
}
#endif

static int
redrawLineRegion(Buffer *buf, Line *l, int i, int bpos, int epos)
{
    int j, pos, rcol, ncol, delta = 1;
    int column = buf->currentColumn;
    char *p;
    Lineprop *pr;
#ifdef USE_ANSI_COLOR
    Linecolor *pc;
#endif
    int bcol, ecol;
#ifdef USE_COLOR
    Anchor *a;
    ParsedURL url;
    int k, vpos = -1;
#endif

    if (l == NULL)
      return 0;
    pos = columnPos(l, column);
    p = &(l->lineBuf[pos]);
    pr = &(l->propBuf[pos]);
#ifdef USE_ANSI_COLOR
    if (useColor && l->colorBuf)
      pc = &(l->colorBuf[pos]);
    else
      pc = NULL;
#endif
    rcol = COLPOS(l, pos);
    bcol = bpos - pos;
    ecol = epos - pos;

    for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
#ifdef USE_COLOR
      if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
          a = retrieveAnchor(buf->href, l->linenumber, pos + j);
          if (a) {
            parseURL2(a->url, &url, baseURL(buf));
            if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
                for (k = a->start.pos; k < a->end.pos; k++)
                  pr[k - pos] |= PE_VISITED;
            }
            vpos = a->end.pos;
          }
      }
#endif
#ifdef USE_M17N
      delta = wtf_len((wc_uchar *) & p[j]);
#endif
      ncol = COLPOS(l, pos + j + delta);
      if (ncol - column > buf->COLS)
          break;
#ifdef USE_ANSI_COLOR
      if (pc)
          do_color(pc[j]);
#endif
      if (j >= bcol && j < ecol) {
          if (rcol < column) {
            move(i, buf->rootX);
            for (rcol = column; rcol < ncol; rcol++)
                addChar(' ', 0);
            continue;
          }
          move(i, rcol - column + buf->rootX);
          if (p[j] == '\t') {
            for (; rcol < ncol; rcol++)
                addChar(' ', 0);
          }
          else
#ifdef USE_M17N
            addMChar(&p[j], pr[j], delta);
#else
            addChar(p[j], pr[j]);
#endif
      }
      rcol = ncol;
    }
    if (somode) {
      somode = FALSE;
      standend();
    }
    if (ulmode) {
      ulmode = FALSE;
      underlineend();
    }
    if (bomode) {
      bomode = FALSE;
      boldend();
    }
    if (emph_mode) {
      emph_mode = FALSE;
      boldend();
    }

    if (anch_mode) {
      anch_mode = FALSE;
      EFFECT_ANCHOR_END;
    }
    if (imag_mode) {
      imag_mode = FALSE;
      EFFECT_IMAGE_END;
    }
    if (form_mode) {
      form_mode = FALSE;
      EFFECT_FORM_END;
    }
    if (visited_mode) {
      visited_mode = FALSE;
      EFFECT_VISITED_END;
    }
    if (active_mode) {
      active_mode = FALSE;
      EFFECT_ACTIVE_END;
    }
    if (mark_mode) {
      mark_mode = FALSE;
      EFFECT_MARK_END;
    }
    if (graph_mode) {
      graph_mode = FALSE;
      graphend();
    }
#ifdef USE_ANSI_COLOR
    if (color_mode)
      do_color(0);
#endif
    return rcol - column;
}

#define do_effect1(effect,modeflag,action_start,action_end) \
if (m & effect) { \
    if (!modeflag) { \
      action_start; \
      modeflag = TRUE; \
    } \
}

#define do_effect2(effect,modeflag,action_start,action_end) \
if (modeflag) { \
    action_end; \
    modeflag = FALSE; \
}

static void
do_effects(Lineprop m)
{
    /* effect end */
    do_effect2(PE_UNDER, ulmode, underline(), underlineend());
    do_effect2(PE_STAND, somode, standout(), standend());
    do_effect2(PE_BOLD, bomode, bold(), boldend());
    do_effect2(PE_EMPH, emph_mode, bold(), boldend());
    do_effect2(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
    do_effect2(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
    do_effect2(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
    do_effect2(PE_VISITED, visited_mode, EFFECT_VISITED_START,
             EFFECT_VISITED_END);
    do_effect2(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
    do_effect2(PE_MARK, mark_mode, EFFECT_MARK_START, EFFECT_MARK_END);
    if (graph_mode) {
      graphend();
      graph_mode = FALSE;
    }

    /* effect start */
    do_effect1(PE_UNDER, ulmode, underline(), underlineend());
    do_effect1(PE_STAND, somode, standout(), standend());
    do_effect1(PE_BOLD, bomode, bold(), boldend());
    do_effect1(PE_EMPH, emph_mode, bold(), boldend());
    do_effect1(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
    do_effect1(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
    do_effect1(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
    do_effect1(PE_VISITED, visited_mode, EFFECT_VISITED_START,
             EFFECT_VISITED_END);
    do_effect1(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
    do_effect1(PE_MARK, mark_mode, EFFECT_MARK_START, EFFECT_MARK_END);
}

#ifdef USE_ANSI_COLOR
static void
do_color(Linecolor c)
{
    if (c & 0x8)
      setfcolor(c & 0x7);
    else if (color_mode & 0x8)
      setfcolor(basic_color);
#ifdef USE_BG_COLOR
    if (c & 0x80)
      setbcolor((c >> 4) & 0x7);
    else if (color_mode & 0x80)
      setbcolor(bg_color);
#endif
    color_mode = c;
}
#endif

#ifdef USE_M17N
void
addChar(char c, Lineprop mode)
{
    addMChar(&c, mode, 1);
}

void
addMChar(char *p, Lineprop mode, size_t len)
#else
void
addChar(char c, Lineprop mode)
#endif
{
    Lineprop m = CharEffect(mode);
#ifdef USE_M17N
    char c = *p;

    if (mode & PC_WCHAR2)
      return;
#endif
    do_effects(m);
    if (mode & PC_SYMBOL) {
      char **symbol;
#ifdef USE_M17N
      int w = (mode & PC_KANJI) ? 2 : 1;

      c = ((char)wtf_get_code((wc_uchar *) p) & 0x7f) - SYMBOL_BASE;
#else
      c -= SYMBOL_BASE;
#endif
      if (graph_ok() && c < N_GRAPH_SYMBOL) {
          if (!graph_mode) {
            graphstart();
            graph_mode = TRUE;
          }
#ifdef USE_M17N
          if (w == 2 && WcOption.use_wide)
            addstr(graph2_symbol[(int)c]);
          else
#endif
            addch(*graph_symbol[(int)c]);
      }
      else {
#ifdef USE_M17N
          symbol = get_symbol(DisplayCharset, &w);
          addstr(symbol[(int)c]);
#else
          symbol = get_symbol();
          addch(*symbol[(int)c]);
#endif
      }
    }
    else if (mode & PC_CTRL) {
      switch (c) {
      case '\t':
          addch(c);
          break;
      case '\n':
          addch(' ');
          break;
      case '\r':
          break;
      case DEL_CODE:
          addstr("^?");
          break;
      default:
          addch('^');
          addch(c + '@');
          break;
      }
    }
#ifdef USE_M17N
    else if (mode & PC_UNKNOWN) {
      char buf[5];
      sprintf(buf, "[%.2X]",
            (unsigned char)wtf_get_code((wc_uchar *) p) | 0x80);
      addstr(buf);
    }
    else
      addmch(p, len);
#else
    else if (0x80 <= (unsigned char)c && (unsigned char)c <= NBSP_CODE)
      addch(' ');
    else
      addch(c);
#endif
}

static GeneralList *message_list = NULL;

void
record_err_message(char *s)
{
    if (fmInitialized) {
      if (!message_list)
          message_list = newGeneralList();
      if (message_list->nitem >= LINES)
          popValue(message_list);
      pushValue(message_list, allocStr(s, -1));
    }
}

/* 
 * List of error messages
 */
Buffer *
message_list_panel(void)
{
    Str tmp = Strnew_size(LINES * COLS);
    ListItem *p;

    /* FIXME: gettextize? */
    Strcat_charp(tmp,
             "<html><head><title>List of error messages</title></head><body>"
             "<h1>List of error messages</h1><table cellpadding=0>\n");
    if (message_list)
      for (p = message_list->last; p; p = p->prev)
          Strcat_m_charp(tmp, "<tr><td><pre>", html_quote(p->ptr),
                     "</pre></td></tr>\n", NULL);
    else
      Strcat_charp(tmp, "<tr><td>(no message recorded)</td></tr>\n");
    Strcat_charp(tmp, "</table></body></html>");
    return loadHTMLString(tmp);
}

void
message(char *s, int return_x, int return_y)
{
    if (!fmInitialized)
      return;
    move(LASTLINE, 0);
    addnstr(s, COLS - 1);
    clrtoeolx();
    move(return_y, return_x);
}

void
disp_err_message(char *s, int redraw_current)
{
    record_err_message(s);
    disp_message(s, redraw_current);
}

void
disp_message_nsec(char *s, int redraw_current, int sec, int purge, int mouse)
{
    if (QuietMessage)
      return;
    if (!fmInitialized) {
      fprintf(stderr, "%s\n", conv_to_system(s));
      return;
    }
    if (CurrentTab != NULL && Currentbuf != NULL)
      message(s, Currentbuf->cursorX + Currentbuf->rootX,
            Currentbuf->cursorY + Currentbuf->rootY);
    else
      message(s, LASTLINE, 0);
    refresh();
#ifdef USE_MOUSE
    if (mouse && use_mouse)
      mouse_active();
#endif
    sleep_till_anykey(sec, purge);
#ifdef USE_MOUSE
    if (mouse && use_mouse)
      mouse_inactive();
#endif
    if (CurrentTab != NULL && Currentbuf != NULL && redraw_current)
      displayBuffer(Currentbuf, B_NORMAL);
}

void
disp_message(char *s, int redraw_current)
{
    disp_message_nsec(s, redraw_current, 10, FALSE, TRUE);
}
#ifdef USE_MOUSE
void
disp_message_nomouse(char *s, int redraw_current)
{
    disp_message_nsec(s, redraw_current, 10, FALSE, FALSE);
}
#endif

void
set_delayed_message(char *s)
{
    delayed_msg = allocStr(s, -1);
}

void
cursorUp0(Buffer *buf, int n)
{
    if (buf->cursorY > 0)
      cursorUpDown(buf, -1);
    else {
      buf->topLine = lineSkip(buf, buf->topLine, -n, FALSE);
      if (buf->currentLine->prev != NULL)
          buf->currentLine = buf->currentLine->prev;
      arrangeLine(buf);
    }
}

void
cursorUp(Buffer *buf, int n)
{
    Line *l = buf->currentLine;
    if (buf->firstLine == NULL)
      return;
    while (buf->currentLine->prev && buf->currentLine->bpos)
      cursorUp0(buf, n);
    if (buf->currentLine == buf->firstLine) {
      gotoLine(buf, l->linenumber);
      arrangeLine(buf);
      return;
    }
    cursorUp0(buf, n);
    while (buf->currentLine->prev && buf->currentLine->bpos &&
         buf->currentLine->bwidth >= buf->currentColumn + buf->visualpos)
      cursorUp0(buf, n);
}

void
cursorDown0(Buffer *buf, int n)
{
    if (buf->cursorY < buf->LINES - 1)
      cursorUpDown(buf, 1);
    else {
      buf->topLine = lineSkip(buf, buf->topLine, n, FALSE);
      if (buf->currentLine->next != NULL)
          buf->currentLine = buf->currentLine->next;
      arrangeLine(buf);
    }
}

void
cursorDown(Buffer *buf, int n)
{
    Line *l = buf->currentLine;
    if (buf->firstLine == NULL)
      return;
    while (buf->currentLine->next && buf->currentLine->next->bpos)
      cursorDown0(buf, n);
    if (buf->currentLine == buf->lastLine) {
      gotoLine(buf, l->linenumber);
      arrangeLine(buf);
      return;
    }
    cursorDown0(buf, n);
    while (buf->currentLine->next && buf->currentLine->next->bpos &&
         buf->currentLine->bwidth + buf->currentLine->width <
         buf->currentColumn + buf->visualpos)
      cursorDown0(buf, n);
}

void
cursorUpDown(Buffer *buf, int n)
{
    Line *cl = buf->currentLine;

    if (buf->firstLine == NULL)
      return;
    if ((buf->currentLine = currentLineSkip(buf, cl, n, FALSE)) == cl)
      return;
    arrangeLine(buf);
}

void
cursorRight(Buffer *buf, int n)
{
    int i, delta = 1, cpos, vpos2;
    Line *l = buf->currentLine;
    Lineprop *p;

    if (buf->firstLine == NULL)
      return;
    if (buf->pos == l->len && !(l->next && l->next->bpos))
      return;
    i = buf->pos;
    p = l->propBuf;
#ifdef USE_M17N
    while (i + delta < l->len && p[i + delta] & PC_WCHAR2)
      delta++;
#endif
    if (i + delta < l->len) {
      buf->pos = i + delta;
    }
    else if (l->len == 0) {
      buf->pos = 0;
    }
    else if (l->next && l->next->bpos) {
      cursorDown0(buf, 1);
      buf->pos = 0;
      arrangeCursor(buf);
      return;
    }
    else {
      buf->pos = l->len - 1;
#ifdef USE_M17N
      while (buf->pos && p[buf->pos] & PC_WCHAR2)
          buf->pos--;
#endif
    }
    cpos = COLPOS(l, buf->pos);
    buf->visualpos = l->bwidth + cpos - buf->currentColumn;
    delta = 1;
#ifdef USE_M17N
    while (buf->pos + delta < l->len && p[buf->pos + delta] & PC_WCHAR2)
      delta++;
#endif
    vpos2 = COLPOS(l, buf->pos + delta) - buf->currentColumn - 1;
    if (vpos2 >= buf->COLS && n) {
      columnSkip(buf, n + (vpos2 - buf->COLS) - (vpos2 - buf->COLS) % n);
      buf->visualpos = l->bwidth + cpos - buf->currentColumn;
    }
    buf->cursorX = buf->visualpos - l->bwidth;
}

void
cursorLeft(Buffer *buf, int n)
{
    int i, delta = 1, cpos;
    Line *l = buf->currentLine;
    Lineprop *p;

    if (buf->firstLine == NULL)
      return;
    i = buf->pos;
    p = l->propBuf;
#ifdef USE_M17N
    while (i - delta > 0 && p[i - delta] & PC_WCHAR2)
      delta++;
#endif
    if (i >= delta)
      buf->pos = i - delta;
    else if (l->prev && l->bpos) {
      cursorUp0(buf, -1);
      buf->pos = buf->currentLine->len - 1;
      arrangeCursor(buf);
      return;
    }
    else
      buf->pos = 0;
    cpos = COLPOS(l, buf->pos);
    buf->visualpos = l->bwidth + cpos - buf->currentColumn;
    if (buf->visualpos - l->bwidth < 0 && n) {
      columnSkip(buf,
               -n + buf->visualpos - l->bwidth - (buf->visualpos -
                                          l->bwidth) % n);
      buf->visualpos = l->bwidth + cpos - buf->currentColumn;
    }
    buf->cursorX = buf->visualpos - l->bwidth;
}

void
cursorHome(Buffer *buf)
{
    buf->visualpos = 0;
    buf->cursorX = buf->cursorY = 0;
}


/* 
 * Arrange line,column and cursor position according to current line and
 * current position.
 */
void
arrangeCursor(Buffer *buf)
{
    int col, col2, pos;
    int delta = 1;
    if (buf == NULL || buf->currentLine == NULL)
      return;
    /* Arrange line */
    if (buf->currentLine->linenumber - buf->topLine->linenumber >= buf->LINES
      || buf->currentLine->linenumber < buf->topLine->linenumber) {
      /*
       * buf->topLine = buf->currentLine;
       */
      buf->topLine = lineSkip(buf, buf->currentLine, 0, FALSE);
    }
    /* Arrange column */
    while (buf->pos < 0 && buf->currentLine->prev && buf->currentLine->bpos) {
      pos = buf->pos + buf->currentLine->prev->len;
      cursorUp0(buf, 1);
      buf->pos = pos;
    }
    while (buf->pos >= buf->currentLine->len && buf->currentLine->next &&
         buf->currentLine->next->bpos) {
      pos = buf->pos - buf->currentLine->len;
      cursorDown0(buf, 1);
      buf->pos = pos;
    }
    if (buf->currentLine->len == 0 || buf->pos < 0)
      buf->pos = 0;
    else if (buf->pos >= buf->currentLine->len)
      buf->pos = buf->currentLine->len - 1;
#ifdef USE_M17N
    while (buf->pos > 0 && buf->currentLine->propBuf[buf->pos] & PC_WCHAR2)
      buf->pos--;
#endif
    col = COLPOS(buf->currentLine, buf->pos);
#ifdef USE_M17N
    while (buf->pos + delta < buf->currentLine->len &&
         buf->currentLine->propBuf[buf->pos + delta] & PC_WCHAR2)
      delta++;
#endif
    col2 = COLPOS(buf->currentLine, buf->pos + delta);
    if (col < buf->currentColumn || col2 > buf->COLS + buf->currentColumn) {
      buf->currentColumn = 0;
      if (col2 > buf->COLS)
          columnSkip(buf, col);
    }
    /* Arrange cursor */
    buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
    buf->visualpos = buf->currentLine->bwidth +
      COLPOS(buf->currentLine, buf->pos) - buf->currentColumn;
    buf->cursorX = buf->visualpos - buf->currentLine->bwidth;
#ifdef DISPLAY_DEBUG
    fprintf(stderr,
          "arrangeCursor: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
          buf->currentColumn, buf->cursorX, buf->visualpos, buf->pos,
          buf->currentLine->len);
#endif
}

void
arrangeLine(Buffer *buf)
{
    int i, cpos;

    if (buf->firstLine == NULL)
      return;
    buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
    i = columnPos(buf->currentLine, buf->currentColumn + buf->visualpos
              - buf->currentLine->bwidth);
    cpos = COLPOS(buf->currentLine, i) - buf->currentColumn;
    if (cpos >= 0) {
      buf->cursorX = cpos;
      buf->pos = i;
    }
    else if (buf->currentLine->len > i) {
      buf->cursorX = 0;
      buf->pos = i + 1;
    }
    else {
      buf->cursorX = 0;
      buf->pos = 0;
    }
#ifdef DISPLAY_DEBUG
    fprintf(stderr,
          "arrangeLine: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
          buf->currentColumn, buf->cursorX, buf->visualpos, buf->pos,
          buf->currentLine->len);
#endif
}

void
cursorXY(Buffer *buf, int x, int y)
{
    int oldX;

    cursorUpDown(buf, y - buf->cursorY);

    if (buf->cursorX > x) {
      while (buf->cursorX > x)
          cursorLeft(buf, buf->COLS / 2);
    }
    else if (buf->cursorX < x) {
      while (buf->cursorX < x) {
          oldX = buf->cursorX;

          cursorRight(buf, buf->COLS / 2);

          if (oldX == buf->cursorX)
            break;
      }
      if (buf->cursorX > x)
          cursorLeft(buf, buf->COLS / 2);
    }
}

void
restorePosition(Buffer *buf, Buffer *orig)
{
    buf->topLine = lineSkip(buf, buf->firstLine, TOP_LINENUMBER(orig) - 1,
                      FALSE);
    gotoLine(buf, CUR_LINENUMBER(orig));
    buf->pos = orig->pos;
    if (buf->currentLine && orig->currentLine)
      buf->pos += orig->currentLine->bpos - buf->currentLine->bpos;
    buf->currentColumn = orig->currentColumn;
    arrangeCursor(buf);
}

/* Local Variables:    */
/* c-basic-offset: 4   */
/* tab-width: 8        */
/* End:                */

Generated by  Doxygen 1.6.0   Back to index