Intial commit
[profile/ivi/w3m.git] / display.c
1 /* $Id: display.c,v 1.70 2007/05/29 12:07:02 inu Exp $ */
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          ((buf->type && !strcmp(buf->type, "text/html")) || 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:                */