w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

display.c (36786B)


      1 /* $Id$ */
      2 #include <signal.h>
      3 #include "fm.h"
      4 
      5 /* *INDENT-OFF* */
      6 #ifdef USE_COLOR
      7 
      8 #define EFFECT_ANCHOR_START       effect_anchor_start()
      9 #define EFFECT_ANCHOR_END         effect_anchor_end()
     10 #define EFFECT_IMAGE_START        effect_image_start()
     11 #define EFFECT_IMAGE_END          effect_image_end()
     12 #define EFFECT_FORM_START         effect_form_start()
     13 #define EFFECT_FORM_END           effect_form_end()
     14 #define EFFECT_ACTIVE_START	  effect_active_start()
     15 #define EFFECT_ACTIVE_END	  effect_active_end()
     16 #define EFFECT_VISITED_START      effect_visited_start()
     17 #define EFFECT_VISITED_END        effect_visited_end()
     18 #define EFFECT_MARK_START         effect_mark_start()
     19 #define EFFECT_MARK_END           effect_mark_end()
     20 
     21 /*-
     22  * color: 
     23  *     0  black 
     24  *     1  red 
     25  *     2  green 
     26  *     3  yellow
     27  *     4  blue 
     28  *     5  magenta 
     29  *     6  cyan 
     30  *     7  white 
     31  */
     32 
     33 #define EFFECT_ANCHOR_START_C       setfcolor(anchor_color)
     34 #define EFFECT_IMAGE_START_C        setfcolor(image_color)
     35 #define EFFECT_FORM_START_C         setfcolor(form_color)
     36 #define EFFECT_ACTIVE_START_C      (setfcolor(active_color), underline())
     37 #define EFFECT_VISITED_START_C      setfcolor(visited_color)
     38 #ifdef USE_BG_COLOR
     39 #define EFFECT_MARK_START_C         setbcolor(mark_color)
     40 #else
     41 #define EFFECT_MARK_START_C         standout()
     42 #endif
     43 
     44 #define EFFECT_IMAGE_END_C          setfcolor(basic_color)
     45 #define EFFECT_ANCHOR_END_C         setfcolor(basic_color)
     46 #define EFFECT_FORM_END_C           setfcolor(basic_color)
     47 #define EFFECT_ACTIVE_END_C        (setfcolor(basic_color), underlineend())
     48 #define EFFECT_VISITED_END_C        setfcolor(basic_color)
     49 #ifdef USE_BG_COLOR
     50 #define EFFECT_MARK_END_C           setbcolor(bg_color)
     51 #else
     52 #define EFFECT_MARK_END_C           standend()
     53 #endif
     54 
     55 #define EFFECT_ANCHOR_START_M       underline()
     56 #define EFFECT_ANCHOR_END_M         underlineend()
     57 #define EFFECT_IMAGE_START_M        standout()
     58 #define EFFECT_IMAGE_END_M          standend()
     59 #define EFFECT_FORM_START_M         standout()
     60 #define EFFECT_FORM_END_M           standend()
     61 #define EFFECT_ACTIVE_START_NC      underline()
     62 #define EFFECT_ACTIVE_END_NC        underlineend()
     63 #define EFFECT_ACTIVE_START_M       bold()
     64 #define EFFECT_ACTIVE_END_M         boldend()
     65 #define EFFECT_VISITED_START_M /**/
     66 #define EFFECT_VISITED_END_M /**/
     67 #define EFFECT_MARK_START_M         standout()
     68 #define EFFECT_MARK_END_M           standend()
     69 #define define_effect(name_start,name_end,color_start,color_end,mono_start,mono_end) \
     70 static void name_start { if (useColor) { color_start; } else { mono_start; }}\
     71 static void name_end { if (useColor) { color_end; } else { mono_end; }}
     72 
     73 define_effect(EFFECT_ANCHOR_START, EFFECT_ANCHOR_END, EFFECT_ANCHOR_START_C,
     74 	      EFFECT_ANCHOR_END_C, EFFECT_ANCHOR_START_M, EFFECT_ANCHOR_END_M)
     75 define_effect(EFFECT_IMAGE_START, EFFECT_IMAGE_END, EFFECT_IMAGE_START_C,
     76 	      EFFECT_IMAGE_END_C, EFFECT_IMAGE_START_M, EFFECT_IMAGE_END_M)
     77 define_effect(EFFECT_FORM_START, EFFECT_FORM_END, EFFECT_FORM_START_C,
     78 	      EFFECT_FORM_END_C, EFFECT_FORM_START_M, EFFECT_FORM_END_M)
     79 define_effect(EFFECT_MARK_START, EFFECT_MARK_END, EFFECT_MARK_START_C,
     80 	      EFFECT_MARK_END_C, EFFECT_MARK_START_M, EFFECT_MARK_END_M)
     81 
     82 /*****************/
     83 static void
     84 EFFECT_ACTIVE_START
     85 {
     86     if (useColor) {
     87 	if (useActiveColor) {
     88 #ifdef __EMX__
     89 	    if(!getenv("WINDOWID"))
     90 		setfcolor(active_color);
     91 	    else
     92 #endif
     93 	    {
     94 		EFFECT_ACTIVE_START_C;
     95 	    }
     96 	} else {
     97 	    EFFECT_ACTIVE_START_NC;
     98 	}
     99     } else {
    100 	EFFECT_ACTIVE_START_M;
    101     }
    102 }
    103 
    104 static void
    105 EFFECT_ACTIVE_END
    106 {
    107     if (useColor) {
    108 	if (useActiveColor) {
    109 	    EFFECT_ACTIVE_END_C;
    110 	} else {
    111 	    EFFECT_ACTIVE_END_NC;
    112 	}
    113     } else {
    114 	EFFECT_ACTIVE_END_M;
    115     }
    116 }
    117 
    118 static void
    119 EFFECT_VISITED_START
    120 {
    121     if (useVisitedColor) {
    122 	if (useColor) {
    123 	    EFFECT_VISITED_START_C;
    124 	} else {
    125 	    EFFECT_VISITED_START_M;
    126 	}
    127     }
    128 }
    129 
    130 static void
    131 EFFECT_VISITED_END
    132 {
    133     if (useVisitedColor) {
    134 	if (useColor) {
    135 	    EFFECT_VISITED_END_C;
    136 	} else {
    137 	    EFFECT_VISITED_END_M;
    138 	}
    139     }
    140 }
    141 
    142 #else				/* not USE_COLOR */
    143 
    144 #define EFFECT_ANCHOR_START       underline()
    145 #define EFFECT_ANCHOR_END         underlineend()
    146 #define EFFECT_IMAGE_START        standout()
    147 #define EFFECT_IMAGE_END          standend()
    148 #define EFFECT_FORM_START         standout()
    149 #define EFFECT_FORM_END           standend()
    150 #define EFFECT_ACTIVE_START       bold()
    151 #define EFFECT_ACTIVE_END         boldend()
    152 #define EFFECT_VISITED_START /**/
    153 #define EFFECT_VISITED_END /**/
    154 #define EFFECT_MARK_START         standout()
    155 #define EFFECT_MARK_END           standend()
    156 #endif				/* not USE_COLOR */
    157 /* *INDENT-ON* */
    158 
    159 void
    160 fmTerm(void)
    161 {
    162     if (fmInitialized) {
    163 	move(LASTLINE, 0);
    164 	clrtoeolx();
    165 	refresh();
    166 #ifdef USE_IMAGE
    167 	if (activeImage)
    168 	    loadImage(NULL, IMG_FLAG_STOP);
    169 #endif
    170 #ifdef USE_MOUSE
    171 	if (use_mouse)
    172 	    mouse_end();
    173 #endif				/* USE_MOUSE */
    174 	reset_tty();
    175 	fmInitialized = FALSE;
    176     }
    177 }
    178 
    179 
    180 /* 
    181  * Initialize routine.
    182  */
    183 void
    184 fmInit(void)
    185 {
    186     if (!fmInitialized) {
    187 	initscr();
    188 	term_raw();
    189 	term_noecho();
    190 #ifdef USE_IMAGE
    191 	if (displayImage)
    192 	    initImage();
    193 #endif
    194     }
    195     fmInitialized = TRUE;
    196 }
    197 
    198 /* 
    199  * Display some lines.
    200  */
    201 static Line *cline = NULL;
    202 static int ccolumn = -1;
    203 
    204 static int ulmode = 0, somode = 0, bomode = 0;
    205 static int anch_mode = 0, emph_mode = 0, imag_mode = 0, form_mode = 0,
    206     active_mode = 0, visited_mode = 0, mark_mode = 0, graph_mode = 0;
    207 #ifdef USE_ANSI_COLOR
    208 static Linecolor color_mode = 0;
    209 #endif
    210 
    211 #ifdef USE_BUFINFO
    212 static Buffer *save_current_buf = NULL;
    213 #endif
    214 
    215 static char *delayed_msg = NULL;
    216 
    217 static void drawAnchorCursor(Buffer *buf);
    218 #define redrawBuffer(buf) redrawNLine(buf, LASTLINE)
    219 static void redrawNLine(Buffer *buf, int n);
    220 static Line *redrawLine(Buffer *buf, Line *l, int i);
    221 #ifdef USE_IMAGE
    222 static int image_touch = 0;
    223 static int draw_image_flag = FALSE;
    224 static Line *redrawLineImage(Buffer *buf, Line *l, int i);
    225 #endif
    226 static int redrawLineRegion(Buffer *buf, Line *l, int i, int bpos, int epos);
    227 static void do_effects(Lineprop m);
    228 #ifdef USE_ANSI_COLOR
    229 static void do_color(Linecolor c);
    230 #endif
    231 
    232 static Str
    233 make_lastline_link(Buffer *buf, char *title, char *url)
    234 {
    235     Str s = NULL, u;
    236 #ifdef USE_M17N
    237     Lineprop *pr;
    238 #endif
    239     ParsedURL pu;
    240     char *p;
    241     int l = COLS - 1, i;
    242 
    243     if (title && *title) {
    244 	s = Strnew_m_charp("[", title, "]", NULL);
    245 	for (p = s->ptr; *p; p++) {
    246 	    if (IS_CNTRL(*p) || IS_SPACE(*p))
    247 		*p = ' ';
    248 	}
    249 	if (url)
    250 	    Strcat_charp(s, " ");
    251 	l -= get_Str_strwidth(s);
    252 	if (l <= 0)
    253 	    return s;
    254     }
    255     if (!url)
    256 	return s;
    257     parseURL2(url, &pu, baseURL(buf));
    258     u = parsedURL2Str(&pu);
    259     if (DecodeURL)
    260 	u = Strnew_charp(url_unquote_conv(u->ptr, buf->document_charset));
    261 #ifdef USE_M17N
    262     u = checkType(u, &pr, NULL);
    263 #endif
    264     if (l <= 4 || l >= get_Str_strwidth(u)) {
    265 	if (!s)
    266 	    return u;
    267 	Strcat(s, u);
    268 	return s;
    269     }
    270     if (!s)
    271 	s = Strnew_size(COLS);
    272     i = (l - 2) / 2;
    273 #ifdef USE_M17N
    274     while (i && pr[i] & PC_WCHAR2)
    275 	i--;
    276 #endif
    277     Strcat_charp_n(s, u->ptr, i);
    278     Strcat_charp(s, "..");
    279     i = get_Str_strwidth(u) - (COLS - 1 - get_Str_strwidth(s));
    280 #ifdef USE_M17N
    281     while (i < u->length && pr[i] & PC_WCHAR2)
    282 	i++;
    283 #endif
    284     Strcat_charp(s, &u->ptr[i]);
    285     return s;
    286 }
    287 
    288 static Str
    289 make_lastline_message(Buffer *buf)
    290 {
    291     Str msg, s = NULL;
    292     int sl = 0;
    293 
    294     if (displayLink) {
    295 #ifdef USE_IMAGE
    296 	MapArea *a = retrieveCurrentMapArea(buf);
    297 	if (a)
    298 	    s = make_lastline_link(buf, a->alt, a->url);
    299 	else
    300 #endif
    301 	{
    302 	    Anchor *a = retrieveCurrentAnchor(buf);
    303 	    char *p = NULL;
    304 	    if (a && a->title && *a->title)
    305 		p = a->title;
    306 	    else {
    307 		Anchor *a_img = retrieveCurrentImg(buf);
    308 		if (a_img && a_img->title && *a_img->title)
    309 		    p = a_img->title;
    310 	    }
    311 	    if (p || a)
    312 		s = make_lastline_link(buf, p, a ? a->url : NULL);
    313 	}
    314 	if (s) {
    315 	    sl = get_Str_strwidth(s);
    316 	    if (sl >= COLS - 3)
    317 		return s;
    318 	}
    319     }
    320 
    321 #ifdef USE_MOUSE
    322     if (use_mouse && mouse_action.lastline_str)
    323 	msg = Strnew_charp(mouse_action.lastline_str);
    324     else
    325 #endif				/* not USE_MOUSE */
    326 	msg = Strnew();
    327     if (displayLineInfo && buf->currentLine != NULL && buf->lastLine != NULL) {
    328 	int cl = buf->currentLine->real_linenumber;
    329 	int ll = buf->lastLine->real_linenumber;
    330 	int r = (int)((double)cl * 100.0 / (double)(ll ? ll : 1) + 0.5);
    331 	Strcat(msg, Sprintf("%d/%d (%d%%)", cl, ll, r));
    332     }
    333     else
    334 	/* FIXME: gettextize? */
    335 	Strcat_charp(msg, "Viewing");
    336 #ifdef USE_SSL
    337     if (buf->ssl_certificate)
    338 	Strcat_charp(msg, "[SSL]");
    339 #endif
    340     Strcat_charp(msg, " <");
    341     Strcat_charp(msg, buf->buffername);
    342 
    343     if (s) {
    344 	int l = COLS - 3 - sl;
    345 	if (get_Str_strwidth(msg) > l) {
    346 #ifdef USE_M17N
    347 	    char *p;
    348 	    for (p = msg->ptr; *p; p += get_mclen(p)) {
    349 		l -= get_mcwidth(p);
    350 		if (l < 0)
    351 		    break;
    352 	    }
    353 	    l = p - msg->ptr;
    354 #endif
    355 	    Strtruncate(msg, l);
    356 	}
    357 	Strcat_charp(msg, "> ");
    358 	Strcat(msg, s);
    359     }
    360     else {
    361 	Strcat_charp(msg, ">");
    362     }
    363     return msg;
    364 }
    365 
    366 void
    367 displayBuffer(Buffer *buf, int mode)
    368 {
    369     Str msg;
    370     int ny = 0;
    371 
    372     if (!buf)
    373 	return;
    374     if (buf->topLine == NULL && readBufferCache(buf) == 0) {	/* clear_buffer */
    375 	mode = B_FORCE_REDRAW;
    376     }
    377 
    378     if (buf->width == 0)
    379 	buf->width = INIT_BUFFER_WIDTH;
    380     if (buf->height == 0)
    381 	buf->height = LASTLINE + 1;
    382     if ((buf->width != INIT_BUFFER_WIDTH &&
    383 	 (is_html_type(buf->type) || FoldLine))
    384 	|| buf->need_reshape) {
    385 	buf->need_reshape = TRUE;
    386 	reshapeBuffer(buf);
    387     }
    388     if (showLineNum) {
    389 	if (buf->lastLine && buf->lastLine->real_linenumber > 0)
    390 	    buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
    391 			       / log(10)) + 2;
    392 	if (buf->rootX < 5)
    393 	    buf->rootX = 5;
    394 	if (buf->rootX > COLS)
    395 	    buf->rootX = COLS;
    396     }
    397     else
    398 	buf->rootX = 0;
    399     buf->COLS = COLS - buf->rootX;
    400     if (nTab > 1
    401 #ifdef USE_MOUSE
    402 	|| mouse_action.menu_str
    403 #endif
    404 	) {
    405 	if (mode == B_FORCE_REDRAW || mode == B_REDRAW_IMAGE)
    406 	    calcTabPos();
    407 	ny = LastTab->y + 2;
    408 	if (ny > LASTLINE)
    409 	    ny = LASTLINE;
    410     }
    411     if (buf->rootY != ny || buf->LINES != LASTLINE - ny) {
    412 	buf->rootY = ny;
    413 	buf->LINES = LASTLINE - ny;
    414 	arrangeCursor(buf);
    415 	mode = B_REDRAW_IMAGE;
    416     }
    417     if (mode == B_FORCE_REDRAW || mode == B_SCROLL || mode == B_REDRAW_IMAGE ||
    418 	cline != buf->topLine || ccolumn != buf->currentColumn) {
    419 #ifdef USE_RAW_SCROLL
    420 	if (
    421 #ifdef USE_IMAGE
    422 	       !(activeImage && displayImage && draw_image_flag) &&
    423 #endif
    424 	       mode == B_SCROLL && cline && buf->currentColumn == ccolumn) {
    425 	    int n = buf->topLine->linenumber - cline->linenumber;
    426 	    if (n > 0 && n < buf->LINES) {
    427 		move(LASTLINE, 0);
    428 		clrtoeolx();
    429 		refresh();
    430 		scroll(n);
    431 	    }
    432 	    else if (n < 0 && n > -buf->LINES) {
    433 #if 0 /* defined(__CYGWIN__) */
    434 		move(LASTLINE + n + 1, 0);
    435 		clrtoeolx();
    436 		refresh();
    437 #endif				/* defined(__CYGWIN__) */
    438 		rscroll(-n);
    439 	    }
    440 	    redrawNLine(buf, n);
    441 	}
    442 	else
    443 #endif
    444 	{
    445 #ifdef USE_IMAGE
    446 	    if (activeImage &&
    447 		(mode == B_REDRAW_IMAGE ||
    448 		 cline != buf->topLine || ccolumn != buf->currentColumn)) {
    449 		if (draw_image_flag)
    450 		    clear();
    451 		clearImage();
    452 		loadImage(buf, IMG_FLAG_STOP);
    453 		image_touch++;
    454 		draw_image_flag = FALSE;
    455 	    }
    456 #endif
    457 	    redrawBuffer(buf);
    458 	}
    459 	cline = buf->topLine;
    460 	ccolumn = buf->currentColumn;
    461     }
    462     if (buf->topLine == NULL)
    463 	buf->topLine = buf->firstLine;
    464 
    465 #ifdef USE_IMAGE
    466     if (buf->need_reshape) {
    467 	displayBuffer(buf, B_FORCE_REDRAW);
    468 	return;
    469     }
    470 #endif
    471 
    472     drawAnchorCursor(buf);
    473 
    474     msg = make_lastline_message(buf);
    475     if (buf->firstLine == NULL) {
    476 	/* FIXME: gettextize? */
    477 	Strcat_charp(msg, "\tNo Line");
    478     }
    479     if (delayed_msg != NULL) {
    480 	disp_message(delayed_msg, FALSE);
    481 	delayed_msg = NULL;
    482 	refresh();
    483     }
    484     standout();
    485     message(msg->ptr, buf->cursorX + buf->rootX, buf->cursorY + buf->rootY);
    486     standend();
    487     term_title(conv_to_system(buf->buffername));
    488     refresh();
    489 #ifdef USE_IMAGE
    490     if (activeImage && displayImage && buf->img) {
    491 	drawImage();
    492     }
    493 #endif
    494 #ifdef USE_BUFINFO
    495     if (buf != save_current_buf) {
    496 	saveBufferInfo();
    497 	save_current_buf = buf;
    498     }
    499 #endif
    500 }
    501 
    502 static void
    503 drawAnchorCursor0(Buffer *buf, AnchorList *al, int hseq, int prevhseq,
    504 		  int tline, int eline, int active)
    505 {
    506     int i, j;
    507     Line *l;
    508     Anchor *an;
    509 
    510     l = buf->topLine;
    511     for (j = 0; j < al->nanchor; j++) {
    512 	an = &al->anchors[j];
    513 	if (an->start.line < tline)
    514 	    continue;
    515 	if (an->start.line >= eline)
    516 	    return;
    517 	for (;; l = l->next) {
    518 	    if (l == NULL)
    519 		return;
    520 	    if (l->linenumber == an->start.line)
    521 		break;
    522 	}
    523 	if (hseq >= 0 && an->hseq == hseq) {
    524 	    for (i = an->start.pos; i < an->end.pos; i++) {
    525 		if (l->propBuf[i] & (PE_IMAGE | PE_ANCHOR | PE_FORM)) {
    526 		    if (active)
    527 			l->propBuf[i] |= PE_ACTIVE;
    528 		    else
    529 			l->propBuf[i] &= ~PE_ACTIVE;
    530 		}
    531 	    }
    532 	    if (active)
    533 		redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
    534 				 an->start.pos, an->end.pos);
    535 	}
    536 	else if (prevhseq >= 0 && an->hseq == prevhseq) {
    537 	    if (active)
    538 		redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
    539 				 an->start.pos, an->end.pos);
    540 	}
    541     }
    542 }
    543 
    544 static void
    545 drawAnchorCursor(Buffer *buf)
    546 {
    547     Anchor *an;
    548     int hseq, prevhseq;
    549     int tline, eline;
    550 
    551     if (!buf->firstLine || !buf->hmarklist)
    552 	return;
    553     if (!buf->href && !buf->formitem)
    554 	return;
    555 
    556     an = retrieveCurrentAnchor(buf);
    557     if (!an)
    558 	an = retrieveCurrentMap(buf);
    559     if (an)
    560 	hseq = an->hseq;
    561     else
    562 	hseq = -1;
    563     tline = buf->topLine->linenumber;
    564     eline = tline + buf->LINES;
    565     prevhseq = buf->hmarklist->prevhseq;
    566 
    567     if (buf->href) {
    568 	drawAnchorCursor0(buf, buf->href, hseq, prevhseq, tline, eline, 1);
    569 	drawAnchorCursor0(buf, buf->href, hseq, -1, tline, eline, 0);
    570     }
    571     if (buf->formitem) {
    572 	drawAnchorCursor0(buf, buf->formitem, hseq, prevhseq, tline, eline, 1);
    573 	drawAnchorCursor0(buf, buf->formitem, hseq, -1, tline, eline, 0);
    574     }
    575     buf->hmarklist->prevhseq = hseq;
    576 }
    577 
    578 static void
    579 redrawNLine(Buffer *buf, int n)
    580 {
    581     Line *l;
    582     int i;
    583 
    584 #ifdef USE_COLOR
    585     if (useColor) {
    586 	EFFECT_ANCHOR_END_C;
    587 #ifdef USE_BG_COLOR
    588 	setbcolor(bg_color);
    589 #endif				/* USE_BG_COLOR */
    590     }
    591 #endif				/* USE_COLOR */
    592     if (nTab > 1
    593 #ifdef USE_MOUSE
    594 	|| mouse_action.menu_str
    595 #endif
    596 	) {
    597 	TabBuffer *t;
    598 	int l;
    599 
    600 	move(0, 0);
    601 #ifdef USE_MOUSE
    602 	if (mouse_action.menu_str)
    603 	    addstr(mouse_action.menu_str);
    604 #endif
    605 	clrtoeolx();
    606 	for (t = FirstTab; t; t = t->nextTab) {
    607 	    move(t->y, t->x1);
    608 	    if (t == CurrentTab)
    609 		bold();
    610 	    addch('[');
    611 	    l = t->x2 - t->x1 - 1 - get_strwidth(t->currentBuffer->buffername);
    612 	    if (l < 0)
    613 		l = 0;
    614 	    if (l / 2 > 0)
    615 		addnstr_sup(" ", l / 2);
    616 	    if (t == CurrentTab)
    617 		EFFECT_ACTIVE_START;
    618 	    addnstr(t->currentBuffer->buffername, t->x2 - t->x1 - l);
    619 	    if (t == CurrentTab)
    620 		EFFECT_ACTIVE_END;
    621 	    if ((l + 1) / 2 > 0)
    622 		addnstr_sup(" ", (l + 1) / 2);
    623 	    move(t->y, t->x2);
    624 	    addch(']');
    625 	    if (t == CurrentTab)
    626 		boldend();
    627 	}
    628 #if 0
    629 	move(0, COLS - 2);
    630 	addstr(" x");
    631 #endif
    632 	move(LastTab->y + 1, 0);
    633 	for (i = 0; i < COLS; i++)
    634 	    addch('~');
    635     }
    636     for (i = 0, l = buf->topLine; i < buf->LINES; i++, l = l->next) {
    637 	if (i >= buf->LINES - n || i < -n)
    638 	    l = redrawLine(buf, l, i + buf->rootY);
    639 	if (l == NULL)
    640 	    break;
    641     }
    642     if (n > 0) {
    643 	move(i + buf->rootY, 0);
    644 	clrtobotx();
    645     }
    646 
    647 #ifdef USE_IMAGE
    648     if (!(activeImage && displayImage && buf->img))
    649 	return;
    650     move(buf->cursorY + buf->rootY, buf->cursorX + buf->rootX);
    651     for (i = 0, l = buf->topLine; i < buf->LINES && l; i++, l = l->next) {
    652 	if (i >= buf->LINES - n || i < -n)
    653 	    redrawLineImage(buf, l, i + buf->rootY);
    654     }
    655     getAllImage(buf);
    656 #endif
    657 }
    658 
    659 static Line *
    660 redrawLine(Buffer *buf, Line *l, int i)
    661 {
    662     int j, pos, rcol, ncol, delta = 1;
    663     int column = buf->currentColumn;
    664     char *p;
    665     Lineprop *pr;
    666 #ifdef USE_ANSI_COLOR
    667     Linecolor *pc;
    668 #endif
    669 #ifdef USE_COLOR
    670     Anchor *a;
    671     ParsedURL url;
    672     int k, vpos = -1;
    673 #endif
    674 
    675     if (l == NULL) {
    676 	if (buf->pagerSource) {
    677 	    l = getNextPage(buf, buf->LINES + buf->rootY - i);
    678 	    if (l == NULL)
    679 		return NULL;
    680 	}
    681 	else
    682 	    return NULL;
    683     }
    684     move(i, 0);
    685     if (showLineNum) {
    686 	char tmp[16];
    687 	if (!buf->rootX) {
    688 	    if (buf->lastLine->real_linenumber > 0)
    689 		buf->rootX = (int)(log(buf->lastLine->real_linenumber + 0.1)
    690 				   / log(10)) + 2;
    691 	    if (buf->rootX < 5)
    692 		buf->rootX = 5;
    693 	    if (buf->rootX > COLS)
    694 		buf->rootX = COLS;
    695 	    buf->COLS = COLS - buf->rootX;
    696 	}
    697 	if (l->real_linenumber && !l->bpos)
    698 	    sprintf(tmp, "%*ld:", buf->rootX - 1, l->real_linenumber);
    699 	else
    700 	    sprintf(tmp, "%*s ", buf->rootX - 1, "");
    701 	addstr(tmp);
    702     }
    703     move(i, buf->rootX);
    704     if (l->width < 0)
    705 	l->width = COLPOS(l, l->len);
    706     if (l->len == 0 || l->width - 1 < column) {
    707 	clrtoeolx();
    708 	return l;
    709     }
    710     /* need_clrtoeol(); */
    711     pos = columnPos(l, column);
    712     p = &(l->lineBuf[pos]);
    713     pr = &(l->propBuf[pos]);
    714 #ifdef USE_ANSI_COLOR
    715     if (useColor && l->colorBuf)
    716 	pc = &(l->colorBuf[pos]);
    717     else
    718 	pc = NULL;
    719 #endif
    720     rcol = COLPOS(l, pos);
    721 
    722     for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
    723 #ifdef USE_COLOR
    724 	if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
    725 	    a = retrieveAnchor(buf->href, l->linenumber, pos + j);
    726 	    if (a) {
    727 		parseURL2(a->url, &url, baseURL(buf));
    728 		if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
    729 		    for (k = a->start.pos; k < a->end.pos; k++)
    730 			pr[k - pos] |= PE_VISITED;
    731 		}
    732 		vpos = a->end.pos;
    733 	    }
    734 	}
    735 #endif
    736 #ifdef USE_M17N
    737 	delta = wtf_len((wc_uchar *) & p[j]);
    738 #endif
    739 	ncol = COLPOS(l, pos + j + delta);
    740 	if (ncol - column > buf->COLS)
    741 	    break;
    742 #ifdef USE_ANSI_COLOR
    743 	if (pc)
    744 	    do_color(pc[j]);
    745 #endif
    746 	if (rcol < column) {
    747 	    for (rcol = column; rcol < ncol; rcol++)
    748 		addChar(' ', 0);
    749 	    continue;
    750 	}
    751 	if (p[j] == '\t') {
    752 	    for (; rcol < ncol; rcol++)
    753 		addChar(' ', 0);
    754 	}
    755 	else {
    756 #ifdef USE_M17N
    757 	    addMChar(&p[j], pr[j], delta);
    758 #else
    759 	    addChar(p[j], pr[j]);
    760 #endif
    761 	}
    762 	rcol = ncol;
    763     }
    764     if (somode) {
    765 	somode = FALSE;
    766 	standend();
    767     }
    768     if (ulmode) {
    769 	ulmode = FALSE;
    770 	underlineend();
    771     }
    772     if (bomode) {
    773 	bomode = FALSE;
    774 	boldend();
    775     }
    776     if (emph_mode) {
    777 	emph_mode = FALSE;
    778 	boldend();
    779     }
    780 
    781     if (anch_mode) {
    782 	anch_mode = FALSE;
    783 	EFFECT_ANCHOR_END;
    784     }
    785     if (imag_mode) {
    786 	imag_mode = FALSE;
    787 	EFFECT_IMAGE_END;
    788     }
    789     if (form_mode) {
    790 	form_mode = FALSE;
    791 	EFFECT_FORM_END;
    792     }
    793     if (visited_mode) {
    794 	visited_mode = FALSE;
    795 	EFFECT_VISITED_END;
    796     }
    797     if (active_mode) {
    798 	active_mode = FALSE;
    799 	EFFECT_ACTIVE_END;
    800     }
    801     if (mark_mode) {
    802 	mark_mode = FALSE;
    803 	EFFECT_MARK_END;
    804     }
    805     if (graph_mode) {
    806 	graph_mode = FALSE;
    807 	graphend();
    808     }
    809 #ifdef USE_ANSI_COLOR
    810     if (color_mode)
    811 	do_color(0);
    812 #endif
    813     if (rcol - column < buf->COLS)
    814 	clrtoeolx();
    815     return l;
    816 }
    817 
    818 #ifdef USE_IMAGE
    819 static Line *
    820 redrawLineImage(Buffer *buf, Line *l, int i)
    821 {
    822     int j, pos, rcol;
    823     int column = buf->currentColumn;
    824     Anchor *a;
    825     int x, y, sx, sy, w, h;
    826 
    827     if (l == NULL)
    828 	return NULL;
    829     if (l->width < 0)
    830 	l->width = COLPOS(l, l->len);
    831     if (l->len == 0 || l->width - 1 < column)
    832 	return l;
    833     pos = columnPos(l, column);
    834     rcol = COLPOS(l, pos);
    835     for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j++) {
    836 	if (rcol - column < 0) {
    837 	    rcol = COLPOS(l, pos + j + 1);
    838 	    continue;
    839 	}
    840 	a = retrieveAnchor(buf->img, l->linenumber, pos + j);
    841 	if (a && a->image && a->image->touch < image_touch) {
    842 	    Image *image = a->image;
    843 	    ImageCache *cache;
    844 
    845 	    cache = image->cache = getImage(image, baseURL(buf),
    846 					    buf->image_flag);
    847 	    if (cache) {
    848 		if ((image->width < 0 && cache->width > 0) ||
    849 		    (image->height < 0 && cache->height > 0)) {
    850 		    image->width = cache->width;
    851 		    image->height = cache->height;
    852 		    buf->need_reshape = TRUE;
    853 		}
    854 		x = (int)((rcol - column + buf->rootX) * pixel_per_char);
    855 		y = (int)(i * pixel_per_line);
    856 		sx = (int)((rcol - COLPOS(l, a->start.pos)) * pixel_per_char);
    857 		sy = (int)((l->linenumber - image->y) * pixel_per_line);
    858 		if (sx == 0 && x + image->xoffset >= 0)
    859 		    x += image->xoffset;
    860 		else
    861 		    sx -= image->xoffset;
    862 		if (sy == 0 && y + image->yoffset >= 0)
    863 		    y += image->yoffset;
    864 		else
    865 		    sy -= image->yoffset;
    866 		if (image->width > 0)
    867 		    w = image->width - sx;
    868 		else
    869 		    w = (int)(8 * pixel_per_char - sx);
    870 		if (image->height > 0)
    871 		    h = image->height - sy;
    872 		else
    873 		    h = (int)(pixel_per_line - sy);
    874 		if (w > (int)((buf->rootX + buf->COLS) * pixel_per_char - x))
    875 		    w = (int)((buf->rootX + buf->COLS) * pixel_per_char - x);
    876 		if (h > (int)(LASTLINE * pixel_per_line - y))
    877 		    h = (int)(LASTLINE * pixel_per_line - y);
    878 		addImage(cache, x, y, sx, sy, w, h);
    879 		image->touch = image_touch;
    880 		draw_image_flag = TRUE;
    881 	    }
    882 	}
    883 	rcol = COLPOS(l, pos + j + 1);
    884     }
    885     return l;
    886 }
    887 #endif
    888 
    889 static int
    890 redrawLineRegion(Buffer *buf, Line *l, int i, int bpos, int epos)
    891 {
    892     int j, pos, rcol, ncol, delta = 1;
    893     int column = buf->currentColumn;
    894     char *p;
    895     Lineprop *pr;
    896 #ifdef USE_ANSI_COLOR
    897     Linecolor *pc;
    898 #endif
    899     int bcol, ecol;
    900 #ifdef USE_COLOR
    901     Anchor *a;
    902     ParsedURL url;
    903     int k, vpos = -1;
    904 #endif
    905 
    906     if (l == NULL)
    907 	return 0;
    908     pos = columnPos(l, column);
    909     p = &(l->lineBuf[pos]);
    910     pr = &(l->propBuf[pos]);
    911 #ifdef USE_ANSI_COLOR
    912     if (useColor && l->colorBuf)
    913 	pc = &(l->colorBuf[pos]);
    914     else
    915 	pc = NULL;
    916 #endif
    917     rcol = COLPOS(l, pos);
    918     bcol = bpos - pos;
    919     ecol = epos - pos;
    920 
    921     for (j = 0; rcol - column < buf->COLS && pos + j < l->len; j += delta) {
    922 #ifdef USE_COLOR
    923 	if (useVisitedColor && vpos <= pos + j && !(pr[j] & PE_VISITED)) {
    924 	    a = retrieveAnchor(buf->href, l->linenumber, pos + j);
    925 	    if (a) {
    926 		parseURL2(a->url, &url, baseURL(buf));
    927 		if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
    928 		    for (k = a->start.pos; k < a->end.pos; k++)
    929 			pr[k - pos] |= PE_VISITED;
    930 		}
    931 		vpos = a->end.pos;
    932 	    }
    933 	}
    934 #endif
    935 #ifdef USE_M17N
    936 	delta = wtf_len((wc_uchar *) & p[j]);
    937 #endif
    938 	ncol = COLPOS(l, pos + j + delta);
    939 	if (ncol - column > buf->COLS)
    940 	    break;
    941 #ifdef USE_ANSI_COLOR
    942 	if (pc)
    943 	    do_color(pc[j]);
    944 #endif
    945 	if (j >= bcol && j < ecol) {
    946 	    if (rcol < column) {
    947 		move(i, buf->rootX);
    948 		for (rcol = column; rcol < ncol; rcol++)
    949 		    addChar(' ', 0);
    950 		continue;
    951 	    }
    952 	    move(i, rcol - column + buf->rootX);
    953 	    if (p[j] == '\t') {
    954 		for (; rcol < ncol; rcol++)
    955 		    addChar(' ', 0);
    956 	    }
    957 	    else
    958 #ifdef USE_M17N
    959 		addMChar(&p[j], pr[j], delta);
    960 #else
    961 		addChar(p[j], pr[j]);
    962 #endif
    963 	}
    964 	rcol = ncol;
    965     }
    966     if (somode) {
    967 	somode = FALSE;
    968 	standend();
    969     }
    970     if (ulmode) {
    971 	ulmode = FALSE;
    972 	underlineend();
    973     }
    974     if (bomode) {
    975 	bomode = FALSE;
    976 	boldend();
    977     }
    978     if (emph_mode) {
    979 	emph_mode = FALSE;
    980 	boldend();
    981     }
    982 
    983     if (anch_mode) {
    984 	anch_mode = FALSE;
    985 	EFFECT_ANCHOR_END;
    986     }
    987     if (imag_mode) {
    988 	imag_mode = FALSE;
    989 	EFFECT_IMAGE_END;
    990     }
    991     if (form_mode) {
    992 	form_mode = FALSE;
    993 	EFFECT_FORM_END;
    994     }
    995     if (visited_mode) {
    996 	visited_mode = FALSE;
    997 	EFFECT_VISITED_END;
    998     }
    999     if (active_mode) {
   1000 	active_mode = FALSE;
   1001 	EFFECT_ACTIVE_END;
   1002     }
   1003     if (mark_mode) {
   1004 	mark_mode = FALSE;
   1005 	EFFECT_MARK_END;
   1006     }
   1007     if (graph_mode) {
   1008 	graph_mode = FALSE;
   1009 	graphend();
   1010     }
   1011 #ifdef USE_ANSI_COLOR
   1012     if (color_mode)
   1013 	do_color(0);
   1014 #endif
   1015     return rcol - column;
   1016 }
   1017 
   1018 #define do_effect1(effect,modeflag,action_start,action_end) \
   1019 if (m & effect) { \
   1020     if (!modeflag) { \
   1021 	action_start; \
   1022 	modeflag = TRUE; \
   1023     } \
   1024 }
   1025 
   1026 #define do_effect2(effect,modeflag,action_start,action_end) \
   1027 if (modeflag) { \
   1028     action_end; \
   1029     modeflag = FALSE; \
   1030 }
   1031 
   1032 static void
   1033 do_effects(Lineprop m)
   1034 {
   1035     /* effect end */
   1036     do_effect2(PE_UNDER, ulmode, underline(), underlineend());
   1037     do_effect2(PE_STAND, somode, standout(), standend());
   1038     do_effect2(PE_BOLD, bomode, bold(), boldend());
   1039     do_effect2(PE_EMPH, emph_mode, bold(), boldend());
   1040     do_effect2(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
   1041     do_effect2(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
   1042     do_effect2(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
   1043     do_effect2(PE_VISITED, visited_mode, EFFECT_VISITED_START,
   1044 	       EFFECT_VISITED_END);
   1045     do_effect2(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
   1046     do_effect2(PE_MARK, mark_mode, EFFECT_MARK_START, EFFECT_MARK_END);
   1047     if (graph_mode) {
   1048 	graphend();
   1049 	graph_mode = FALSE;
   1050     }
   1051 
   1052     /* effect start */
   1053     do_effect1(PE_UNDER, ulmode, underline(), underlineend());
   1054     do_effect1(PE_STAND, somode, standout(), standend());
   1055     do_effect1(PE_BOLD, bomode, bold(), boldend());
   1056     do_effect1(PE_EMPH, emph_mode, bold(), boldend());
   1057     do_effect1(PE_ANCHOR, anch_mode, EFFECT_ANCHOR_START, EFFECT_ANCHOR_END);
   1058     do_effect1(PE_IMAGE, imag_mode, EFFECT_IMAGE_START, EFFECT_IMAGE_END);
   1059     do_effect1(PE_FORM, form_mode, EFFECT_FORM_START, EFFECT_FORM_END);
   1060     do_effect1(PE_VISITED, visited_mode, EFFECT_VISITED_START,
   1061 	       EFFECT_VISITED_END);
   1062     do_effect1(PE_ACTIVE, active_mode, EFFECT_ACTIVE_START, EFFECT_ACTIVE_END);
   1063     do_effect1(PE_MARK, mark_mode, EFFECT_MARK_START, EFFECT_MARK_END);
   1064 }
   1065 
   1066 #ifdef USE_ANSI_COLOR
   1067 static void
   1068 do_color(Linecolor c)
   1069 {
   1070     if (c & 0x8)
   1071 	setfcolor(c & 0x7);
   1072     else if (color_mode & 0x8)
   1073 	setfcolor(basic_color);
   1074 #ifdef USE_BG_COLOR
   1075     if (c & 0x80)
   1076 	setbcolor((c >> 4) & 0x7);
   1077     else if (color_mode & 0x80)
   1078 	setbcolor(bg_color);
   1079 #endif
   1080     color_mode = c;
   1081 }
   1082 #endif
   1083 
   1084 #ifdef USE_M17N
   1085 void
   1086 addChar(char c, Lineprop mode)
   1087 {
   1088     addMChar(&c, mode, 1);
   1089 }
   1090 
   1091 void
   1092 addMChar(char *p, Lineprop mode, size_t len)
   1093 #else
   1094 void
   1095 addChar(char c, Lineprop mode)
   1096 #endif
   1097 {
   1098     Lineprop m = CharEffect(mode);
   1099 #ifdef USE_M17N
   1100     char c = *p;
   1101 
   1102     if (mode & PC_WCHAR2)
   1103 	return;
   1104 #endif
   1105     do_effects(m);
   1106     if (mode & PC_SYMBOL) {
   1107 	char **symbol;
   1108 #ifdef USE_M17N
   1109 	int w = (mode & PC_KANJI) ? 2 : 1;
   1110 
   1111 	c = ((char)wtf_get_code((wc_uchar *) p) & 0x7f) - SYMBOL_BASE;
   1112 #else
   1113 	c -= SYMBOL_BASE;
   1114 #endif
   1115 	if (graph_ok() && c < N_GRAPH_SYMBOL) {
   1116 	    if (!graph_mode) {
   1117 		graphstart();
   1118 		graph_mode = TRUE;
   1119 	    }
   1120 #ifdef USE_M17N
   1121 	    if (w == 2 && WcOption.use_wide)
   1122 		addstr(graph2_symbol[(int)c]);
   1123 	    else
   1124 #endif
   1125 		addch(*graph_symbol[(int)c]);
   1126 	}
   1127 	else {
   1128 #ifdef USE_M17N
   1129 	    symbol = get_symbol(DisplayCharset, &w);
   1130 	    addstr(symbol[(int)c]);
   1131 #else
   1132 	    symbol = get_symbol();
   1133 	    addch(*symbol[(int)c]);
   1134 #endif
   1135 	}
   1136     }
   1137     else if (mode & PC_CTRL) {
   1138 	switch (c) {
   1139 	case '\t':
   1140 	    addch(c);
   1141 	    break;
   1142 	case '\n':
   1143 	    addch(' ');
   1144 	    break;
   1145 	case '\r':
   1146 	    break;
   1147 	case DEL_CODE:
   1148 	    addstr("^?");
   1149 	    break;
   1150 	default:
   1151 	    addch('^');
   1152 	    addch(c + '@');
   1153 	    break;
   1154 	}
   1155     }
   1156 #ifdef USE_M17N
   1157     else if (mode & PC_UNKNOWN) {
   1158 	char buf[5];
   1159 	sprintf(buf, "[%.2X]",
   1160 		(unsigned char)wtf_get_code((wc_uchar *) p) | 0x80);
   1161 	addstr(buf);
   1162     }
   1163     else
   1164 	addmch(p, len);
   1165 #else
   1166     else if (0x80 <= (unsigned char)c && (unsigned char)c <= NBSP_CODE)
   1167 	addch(' ');
   1168     else
   1169 	addch(c);
   1170 #endif
   1171 }
   1172 
   1173 static GeneralList *message_list = NULL;
   1174 
   1175 void
   1176 record_err_message(char *s)
   1177 {
   1178     if (fmInitialized) {
   1179 	if (!message_list)
   1180 	    message_list = newGeneralList();
   1181 	if (message_list->nitem >= LINES)
   1182 	    popValue(message_list);
   1183 	pushValue(message_list, allocStr(s, -1));
   1184     }
   1185 }
   1186 
   1187 /* 
   1188  * List of error messages
   1189  */
   1190 Buffer *
   1191 message_list_panel(void)
   1192 {
   1193     Str tmp = Strnew_size(LINES * COLS);
   1194     ListItem *p;
   1195 
   1196     /* FIXME: gettextize? */
   1197     Strcat_charp(tmp,
   1198 		 "<html><head><title>List of error messages</title></head><body>"
   1199 		 "<h1>List of error messages</h1><table cellpadding=0>\n");
   1200     if (message_list)
   1201 	for (p = message_list->last; p; p = p->prev)
   1202 	    Strcat_m_charp(tmp, "<tr><td><pre>", html_quote(p->ptr),
   1203 			   "</pre></td></tr>\n", NULL);
   1204     else
   1205 	Strcat_charp(tmp, "<tr><td>(no message recorded)</td></tr>\n");
   1206     Strcat_charp(tmp, "</table></body></html>");
   1207     return loadHTMLString(tmp);
   1208 }
   1209 
   1210 void
   1211 message(char *s, int return_x, int return_y)
   1212 {
   1213     if (!fmInitialized)
   1214 	return;
   1215     move(LASTLINE, 0);
   1216     addnstr(s, COLS - 1);
   1217     clrtoeolx();
   1218     move(return_y, return_x);
   1219 }
   1220 
   1221 void
   1222 disp_err_message(char *s, int redraw_current)
   1223 {
   1224     record_err_message(s);
   1225     disp_message(s, redraw_current);
   1226 }
   1227 
   1228 void
   1229 disp_message_nsec(char *s, int redraw_current, int sec, int purge, int mouse)
   1230 {
   1231     if (QuietMessage)
   1232 	return;
   1233     if (!fmInitialized) {
   1234 	fprintf(stderr, "%s\n", conv_to_system(s));
   1235 	return;
   1236     }
   1237     if (CurrentTab != NULL && Currentbuf != NULL)
   1238 	message(s, Currentbuf->cursorX + Currentbuf->rootX,
   1239 		Currentbuf->cursorY + Currentbuf->rootY);
   1240     else
   1241 	message(s, LASTLINE, 0);
   1242     refresh();
   1243 #ifdef USE_MOUSE
   1244     if (mouse && use_mouse)
   1245 	mouse_active();
   1246 #endif
   1247     sleep_till_anykey(sec, purge);
   1248 #ifdef USE_MOUSE
   1249     if (mouse && use_mouse)
   1250 	mouse_inactive();
   1251 #endif
   1252     if (CurrentTab != NULL && Currentbuf != NULL && redraw_current)
   1253 	displayBuffer(Currentbuf, B_NORMAL);
   1254 }
   1255 
   1256 void
   1257 disp_message(char *s, int redraw_current)
   1258 {
   1259     disp_message_nsec(s, redraw_current, 10, FALSE, TRUE);
   1260 }
   1261 #ifdef USE_MOUSE
   1262 void
   1263 disp_message_nomouse(char *s, int redraw_current)
   1264 {
   1265     disp_message_nsec(s, redraw_current, 10, FALSE, FALSE);
   1266 }
   1267 #endif
   1268 
   1269 void
   1270 set_delayed_message(char *s)
   1271 {
   1272     delayed_msg = allocStr(s, -1);
   1273 }
   1274 
   1275 void
   1276 cursorUp0(Buffer *buf, int n)
   1277 {
   1278     if (buf->cursorY > 0)
   1279 	cursorUpDown(buf, -1);
   1280     else {
   1281 	buf->topLine = lineSkip(buf, buf->topLine, -n, FALSE);
   1282 	if (buf->currentLine->prev != NULL)
   1283 	    buf->currentLine = buf->currentLine->prev;
   1284 	arrangeLine(buf);
   1285     }
   1286 }
   1287 
   1288 void
   1289 cursorUp(Buffer *buf, int n)
   1290 {
   1291     Line *l = buf->currentLine;
   1292     if (buf->firstLine == NULL)
   1293 	return;
   1294     while (buf->currentLine->prev && buf->currentLine->bpos)
   1295 	cursorUp0(buf, n);
   1296     if (buf->currentLine == buf->firstLine) {
   1297 	gotoLine(buf, l->linenumber);
   1298 	arrangeLine(buf);
   1299 	return;
   1300     }
   1301     cursorUp0(buf, n);
   1302     while (buf->currentLine->prev && buf->currentLine->bpos &&
   1303 	   buf->currentLine->bwidth >= buf->currentColumn + buf->visualpos)
   1304 	cursorUp0(buf, n);
   1305 }
   1306 
   1307 void
   1308 cursorDown0(Buffer *buf, int n)
   1309 {
   1310     if (buf->cursorY < buf->LINES - 1)
   1311 	cursorUpDown(buf, 1);
   1312     else {
   1313 	buf->topLine = lineSkip(buf, buf->topLine, n, FALSE);
   1314 	if (buf->currentLine->next != NULL)
   1315 	    buf->currentLine = buf->currentLine->next;
   1316 	arrangeLine(buf);
   1317     }
   1318 }
   1319 
   1320 void
   1321 cursorDown(Buffer *buf, int n)
   1322 {
   1323     Line *l = buf->currentLine;
   1324     if (buf->firstLine == NULL)
   1325 	return;
   1326     while (buf->currentLine->next && buf->currentLine->next->bpos)
   1327 	cursorDown0(buf, n);
   1328     if (buf->currentLine == buf->lastLine) {
   1329 	gotoLine(buf, l->linenumber);
   1330 	arrangeLine(buf);
   1331 	return;
   1332     }
   1333     cursorDown0(buf, n);
   1334     while (buf->currentLine->next && buf->currentLine->next->bpos &&
   1335 	   buf->currentLine->bwidth + buf->currentLine->width <
   1336 	   buf->currentColumn + buf->visualpos)
   1337 	cursorDown0(buf, n);
   1338 }
   1339 
   1340 void
   1341 cursorUpDown(Buffer *buf, int n)
   1342 {
   1343     Line *cl = buf->currentLine;
   1344 
   1345     if (buf->firstLine == NULL)
   1346 	return;
   1347     if ((buf->currentLine = currentLineSkip(buf, cl, n, FALSE)) == cl)
   1348 	return;
   1349     arrangeLine(buf);
   1350 }
   1351 
   1352 void
   1353 cursorRight(Buffer *buf, int n)
   1354 {
   1355     int i, delta = 1, cpos, vpos2;
   1356     Line *l = buf->currentLine;
   1357     Lineprop *p;
   1358 
   1359     if (buf->firstLine == NULL)
   1360 	return;
   1361     if (buf->pos == l->len && !(l->next && l->next->bpos))
   1362 	return;
   1363     i = buf->pos;
   1364     p = l->propBuf;
   1365 #ifdef USE_M17N
   1366     while (i + delta < l->len && p[i + delta] & PC_WCHAR2)
   1367 	delta++;
   1368 #endif
   1369     if (i + delta < l->len) {
   1370 	buf->pos = i + delta;
   1371     }
   1372     else if (l->len == 0) {
   1373 	buf->pos = 0;
   1374     }
   1375     else if (l->next && l->next->bpos) {
   1376 	cursorDown0(buf, 1);
   1377 	buf->pos = 0;
   1378 	arrangeCursor(buf);
   1379 	return;
   1380     }
   1381     else {
   1382 	buf->pos = l->len - 1;
   1383 #ifdef USE_M17N
   1384 	while (buf->pos && p[buf->pos] & PC_WCHAR2)
   1385 	    buf->pos--;
   1386 #endif
   1387     }
   1388     cpos = COLPOS(l, buf->pos);
   1389     buf->visualpos = l->bwidth + cpos - buf->currentColumn;
   1390     delta = 1;
   1391 #ifdef USE_M17N
   1392     while (buf->pos + delta < l->len && p[buf->pos + delta] & PC_WCHAR2)
   1393 	delta++;
   1394 #endif
   1395     vpos2 = COLPOS(l, buf->pos + delta) - buf->currentColumn - 1;
   1396     if (vpos2 >= buf->COLS && n) {
   1397 	columnSkip(buf, n + (vpos2 - buf->COLS) - (vpos2 - buf->COLS) % n);
   1398 	buf->visualpos = l->bwidth + cpos - buf->currentColumn;
   1399     }
   1400     buf->cursorX = buf->visualpos - l->bwidth;
   1401 }
   1402 
   1403 void
   1404 cursorLeft(Buffer *buf, int n)
   1405 {
   1406     int i, delta = 1, cpos;
   1407     Line *l = buf->currentLine;
   1408     Lineprop *p;
   1409 
   1410     if (buf->firstLine == NULL)
   1411 	return;
   1412     i = buf->pos;
   1413     p = l->propBuf;
   1414 #ifdef USE_M17N
   1415     while (i - delta > 0 && p[i - delta] & PC_WCHAR2)
   1416 	delta++;
   1417 #endif
   1418     if (i >= delta)
   1419 	buf->pos = i - delta;
   1420     else if (l->prev && l->bpos) {
   1421 	cursorUp0(buf, -1);
   1422 	buf->pos = buf->currentLine->len - 1;
   1423 	arrangeCursor(buf);
   1424 	return;
   1425     }
   1426     else
   1427 	buf->pos = 0;
   1428     cpos = COLPOS(l, buf->pos);
   1429     buf->visualpos = l->bwidth + cpos - buf->currentColumn;
   1430     if (buf->visualpos - l->bwidth < 0 && n) {
   1431 	columnSkip(buf,
   1432 		   -n + buf->visualpos - l->bwidth - (buf->visualpos -
   1433 						      l->bwidth) % n);
   1434 	buf->visualpos = l->bwidth + cpos - buf->currentColumn;
   1435     }
   1436     buf->cursorX = buf->visualpos - l->bwidth;
   1437 }
   1438 
   1439 void
   1440 cursorHome(Buffer *buf)
   1441 {
   1442     buf->visualpos = 0;
   1443     buf->cursorX = buf->cursorY = 0;
   1444 }
   1445 
   1446 
   1447 /* 
   1448  * Arrange line,column and cursor position according to current line and
   1449  * current position.
   1450  */
   1451 void
   1452 arrangeCursor(Buffer *buf)
   1453 {
   1454     int col, col2, pos;
   1455     int delta = 1;
   1456     if (buf == NULL || buf->currentLine == NULL)
   1457 	return;
   1458     /* Arrange line */
   1459     if (buf->currentLine->linenumber - buf->topLine->linenumber >= buf->LINES
   1460 	|| buf->currentLine->linenumber < buf->topLine->linenumber) {
   1461 	/*
   1462 	 * buf->topLine = buf->currentLine;
   1463 	 */
   1464 	buf->topLine = lineSkip(buf, buf->currentLine, 0, FALSE);
   1465     }
   1466     /* Arrange column */
   1467     while (buf->pos < 0 && buf->currentLine->prev && buf->currentLine->bpos) {
   1468 	pos = buf->pos + buf->currentLine->prev->len;
   1469 	cursorUp0(buf, 1);
   1470 	buf->pos = pos;
   1471     }
   1472     while (buf->pos >= buf->currentLine->len && buf->currentLine->next &&
   1473 	   buf->currentLine->next->bpos) {
   1474 	pos = buf->pos - buf->currentLine->len;
   1475 	cursorDown0(buf, 1);
   1476 	buf->pos = pos;
   1477     }
   1478     if (buf->currentLine->len == 0 || buf->pos < 0)
   1479 	buf->pos = 0;
   1480     else if (buf->pos >= buf->currentLine->len)
   1481 	buf->pos = buf->currentLine->len - 1;
   1482 #ifdef USE_M17N
   1483     while (buf->pos > 0 && buf->currentLine->propBuf[buf->pos] & PC_WCHAR2)
   1484 	buf->pos--;
   1485 #endif
   1486     col = COLPOS(buf->currentLine, buf->pos);
   1487 #ifdef USE_M17N
   1488     while (buf->pos + delta < buf->currentLine->len &&
   1489 	   buf->currentLine->propBuf[buf->pos + delta] & PC_WCHAR2)
   1490 	delta++;
   1491 #endif
   1492     col2 = COLPOS(buf->currentLine, buf->pos + delta);
   1493     if (col < buf->currentColumn || col2 > buf->COLS + buf->currentColumn) {
   1494 	buf->currentColumn = 0;
   1495 	if (col2 > buf->COLS)
   1496 	    columnSkip(buf, col);
   1497     }
   1498     /* Arrange cursor */
   1499     buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
   1500     buf->visualpos = buf->currentLine->bwidth +
   1501 	COLPOS(buf->currentLine, buf->pos) - buf->currentColumn;
   1502     buf->cursorX = buf->visualpos - buf->currentLine->bwidth;
   1503 #ifdef DISPLAY_DEBUG
   1504     fprintf(stderr,
   1505 	    "arrangeCursor: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
   1506 	    buf->currentColumn, buf->cursorX, buf->visualpos, buf->pos,
   1507 	    buf->currentLine->len);
   1508 #endif
   1509 }
   1510 
   1511 void
   1512 arrangeLine(Buffer *buf)
   1513 {
   1514     int i, cpos;
   1515 
   1516     if (buf->firstLine == NULL)
   1517 	return;
   1518     buf->cursorY = buf->currentLine->linenumber - buf->topLine->linenumber;
   1519     i = columnPos(buf->currentLine, buf->currentColumn + buf->visualpos
   1520 		  - buf->currentLine->bwidth);
   1521     cpos = COLPOS(buf->currentLine, i) - buf->currentColumn;
   1522     if (cpos >= 0) {
   1523 	buf->cursorX = cpos;
   1524 	buf->pos = i;
   1525     }
   1526     else if (buf->currentLine->len > i) {
   1527 	buf->cursorX = 0;
   1528 	buf->pos = i + 1;
   1529     }
   1530     else {
   1531 	buf->cursorX = 0;
   1532 	buf->pos = 0;
   1533     }
   1534 #ifdef DISPLAY_DEBUG
   1535     fprintf(stderr,
   1536 	    "arrangeLine: column=%d, cursorX=%d, visualpos=%d, pos=%d, len=%d\n",
   1537 	    buf->currentColumn, buf->cursorX, buf->visualpos, buf->pos,
   1538 	    buf->currentLine->len);
   1539 #endif
   1540 }
   1541 
   1542 void
   1543 cursorXY(Buffer *buf, int x, int y)
   1544 {
   1545     int oldX;
   1546 
   1547     cursorUpDown(buf, y - buf->cursorY);
   1548 
   1549     if (buf->cursorX > x) {
   1550 	while (buf->cursorX > x)
   1551 	    cursorLeft(buf, buf->COLS / 2);
   1552     }
   1553     else if (buf->cursorX < x) {
   1554 	while (buf->cursorX < x) {
   1555 	    oldX = buf->cursorX;
   1556 
   1557 	    cursorRight(buf, buf->COLS / 2);
   1558 
   1559 	    if (oldX == buf->cursorX)
   1560 		break;
   1561 	}
   1562 	if (buf->cursorX > x)
   1563 	    cursorLeft(buf, buf->COLS / 2);
   1564     }
   1565 }
   1566 
   1567 void
   1568 restorePosition(Buffer *buf, Buffer *orig)
   1569 {
   1570     buf->topLine = lineSkip(buf, buf->firstLine, TOP_LINENUMBER(orig) - 1,
   1571 			    FALSE);
   1572     gotoLine(buf, CUR_LINENUMBER(orig));
   1573     buf->pos = orig->pos;
   1574     if (buf->currentLine && orig->currentLine)
   1575 	buf->pos += orig->currentLine->bpos - buf->currentLine->bpos;
   1576     buf->currentColumn = orig->currentColumn;
   1577     arrangeCursor(buf);
   1578 }
   1579 
   1580 /* Local Variables:    */
   1581 /* c-basic-offset: 4   */
   1582 /* tab-width: 8        */
   1583 /* End:                */