1
/* Copyright (c) 1993-2002
2
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4
* Copyright (c) 1987 Oliver Laumann
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2, or (at your option)
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program (see the file COPYING); if not, write to the
18
* Free Software Foundation, Inc.,
19
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21
****************************************************************
24
#include <sys/types.h>
28
# include <sys/ioctl.h>
36
static int CountChars __P((int));
37
static int DoAddChar __P((int));
38
static int BlankResize __P((int, int));
39
static int CallRewrite __P((int, int, int, int));
40
static void FreeCanvas __P((struct canvas *));
41
static void disp_readev_fn __P((struct event *, char *));
42
static void disp_writeev_fn __P((struct event *, char *));
44
static void disp_writeev_eagain __P((struct event *, char *));
46
static void disp_status_fn __P((struct event *, char *));
47
static void disp_hstatus_fn __P((struct event *, char *));
48
static void disp_blocked_fn __P((struct event *, char *));
49
static void cv_winid_fn __P((struct event *, char *));
51
static void disp_map_fn __P((struct event *, char *));
53
static void disp_idle_fn __P((struct event *, char *));
55
static void disp_blanker_fn __P((struct event *, char *));
57
static void WriteLP __P((int, int));
58
static void INSERTCHAR __P((int));
59
static void RAW_PUTCHAR __P((int));
61
static void SetBackColor __P((int));
65
extern struct layer *flayer;
66
extern struct win *windows, *fore;
67
extern struct LayFuncs WinLf;
69
extern int use_hardstatus;
70
extern int MsgWait, MsgMinWait;
71
extern int Z0width, Z1width;
72
extern unsigned char *blank, *null;
73
extern struct mline mline_blank, mline_null, mline_old;
74
extern struct mchar mchar_null, mchar_blank, mchar_so;
75
extern struct NewWindow nwin_default;
76
extern struct action idleaction;
78
/* XXX shouldn't be here */
79
extern char *hstatusstring;
80
extern char *captionstring;
86
extern int pty_preopen;
87
#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
88
extern struct winsize glwz;
91
extern int real_uid, real_gid;
95
* tputs needs this to calculate the padding
99
#endif /* NEED_OSPEED */
103
struct display *display, *displays;
105
int attr2color[8][4];
110
struct display TheDisplay;
116
int defobuflimit = OBUF_MAX;
117
int defnonblock = -1;
122
int hardstatusemu = HSTATUS_IGNORE;
125
* Default layer management
129
DefProcess(bufp, lenp)
138
DefRedisplayLine(y, xs, xe, isblank)
139
int y, xs, xe, isblank;
141
if (isblank == 0 && y >= 0)
142
DefClearLine(y, xs, xe, 0);
146
DefClearLine(y, xs, xe, bce)
149
LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
154
DefRewrite(y, xs, xe, rend, doit)
172
LAY_DISPLAYS(flayer, InsertMode(0));
173
/* ChangeScrollRegion(0, D_height - 1); */
174
LKeypadMode(flayer, 0);
175
LCursorkeysMode(flayer, 0);
176
LCursorVisibility(flayer, 0);
177
LMouseMode(flayer, 0);
178
LSetRendition(flayer, &mchar_null);
179
LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
183
* Blank layer management
186
struct LayFuncs BlankLf =
202
flayer->l_width = wi;
203
flayer->l_height = he;
209
* Generate new display, start with a blank layer.
210
* The termcap arrays are not initialised here.
211
* The new display is placed in the displays list.
215
MakeDisplay(uname, utty, term, fd, pid, Mode)
216
char *uname, *utty, *term;
221
struct baud_values *b;
223
if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
224
return 0; /* could not find or add user */
227
if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
232
bzero((char *)&TheDisplay, sizeof(TheDisplay));
233
display = &TheDisplay;
235
display->d_next = displays;
238
D_nonblock = defnonblock;
240
D_readev.fd = D_writeev.fd = fd;
241
D_readev.type = EV_READ;
242
D_writeev.type = EV_WRITE;
243
D_readev.data = D_writeev.data = (char *)display;
244
D_readev.handler = disp_readev_fn;
245
D_writeev.handler = disp_writeev_fn;
247
D_writeev.condpos = &D_obuflen;
248
D_writeev.condneg = &D_obuffree;
250
D_statusev.type = EV_TIMEOUT;
251
D_statusev.data = (char *)display;
252
D_statusev.handler = disp_status_fn;
253
D_hstatusev.type = EV_TIMEOUT;
254
D_hstatusev.data = (char *)display;
255
D_hstatusev.handler = disp_hstatus_fn;
256
D_blockedev.type = EV_TIMEOUT;
257
D_blockedev.data = (char *)display;
258
D_blockedev.handler = disp_blocked_fn;
259
D_blockedev.condpos = &D_obuffree;
260
D_blockedev.condneg = &D_obuflenmax;
261
D_hstatusev.handler = disp_hstatus_fn;
263
D_mapev.type = EV_TIMEOUT;
264
D_mapev.data = (char *)display;
265
D_mapev.handler = disp_map_fn;
267
D_idleev.type = EV_TIMEOUT;
268
D_idleev.data = (char *)display;
269
D_idleev.handler = disp_idle_fn;
271
D_blankerev.type = EV_READ;
272
D_blankerev.data = (char *)display;
273
D_blankerev.handler = disp_blanker_fn;
277
D_status_obuffree = -1;
278
Resize_obuf(); /* Allocate memory for buffer */
279
D_obufmax = defobuflimit;
280
D_obuflenmax = D_obuflen - D_obufmax;
282
D_auto_nuke = defautonuke;
289
if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
293
if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
296
D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
299
debug1("New displays ospeed = %d\n", D_dospeed);
301
strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
302
D_usertty[sizeof(D_usertty) - 1] = 0;
303
strncpy(D_termname, term, sizeof(D_termname) - 1);
304
D_termname[sizeof(D_termname) - 1] = 0;
306
D_processinput = ProcessInput;
315
struct canvas *cv, *cvp;
317
struct display *d, **dp;
331
SetTTY(D_userfd, &D_OldMode);
332
fcntl(D_userfd, F_SETFL, 0);
338
if (D_processinputdata)
339
free(D_processinputdata);
340
D_processinputdata = 0;
365
if (bd.bd_dpy == display)
367
bd.bd_start_braille = 0;
373
for (dp = &displays; (d = *dp) ; dp = &d->d_next)
377
if (D_status_lastmsg)
378
free(D_status_lastmsg);
381
*dp = display->d_next;
382
cv = display->d_cvlist;
384
ASSERT(display == displays);
385
ASSERT(display == &TheDisplay);
386
cv = display->d_cvlist;
387
display->d_cvlist = 0;
391
for (p = windows; p; p = p->w_next)
393
if (p->w_pdisplay == display)
395
if (p->w_lastdisp == display)
397
if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
398
p->w_readev.condpos = p->w_readev.condneg = 0;
406
for (p = windows; p; p = p->w_next)
407
if (p->w_zdisplay == display)
411
free((char *)display);
422
if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
425
cv->c_xe = D_width - 1;
427
cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
431
cv->c_display = display;
433
cv->c_captev.type = EV_TIMEOUT;
434
cv->c_captev.data = (char *)cv;
435
cv->c_captev.handler = cv_winid_fn;
437
cv->c_blank.l_cvlist = cv;
438
cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
439
cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
440
cv->c_blank.l_x = cv->c_blank.l_y = 0;
441
cv->c_blank.l_layfn = &BlankLf;
442
cv->c_blank.l_data = 0;
443
cv->c_blank.l_next = 0;
444
cv->c_blank.l_bottom = &cv->c_blank;
445
cv->c_blank.l_blocking = 0;
446
cv->c_layer = &cv->c_blank;
450
RethinkDisplayViewports();
451
D_forecv = cv; /* default input focus */
459
struct viewport *vp, *nvp;
462
p = Layer2Window(cv->c_layer);
463
SetCanvasWindow(cv, 0);
465
WindowChanged(p, 'u');
466
if (flayer == cv->c_layer)
468
for (vp = cv->c_vplist; vp; vp = nvp)
475
evdeq(&cv->c_captev);
483
struct canvas *cv, **cvpp;
485
for (cv = D_cvlist, j = 0; cv; cv = cv->c_next)
487
j++; /* new canvas */
488
h = D_height - (D_has_hstatus == HSTATUS_LASTLINE);
492
for (cv = D_cvlist; cv; cv = cv->c_next)
498
if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
502
cv->c_xe = D_width - 1;
504
cv->c_ye = D_height - 1;
507
cv->c_display = display;
509
cv->c_captev.type = EV_TIMEOUT;
510
cv->c_captev.data = (char *)cv;
511
cv->c_captev.handler = cv_winid_fn;
513
cv->c_blank.l_cvlist = cv;
514
cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
515
cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
516
cv->c_blank.l_x = cv->c_blank.l_y = 0;
517
cv->c_blank.l_layfn = &BlankLf;
518
cv->c_blank.l_data = 0;
519
cv->c_blank.l_next = 0;
520
cv->c_blank.l_bottom = &cv->c_blank;
521
cv->c_blank.l_blocking = 0;
522
cv->c_layer = &cv->c_blank;
529
for (cv = D_cvlist; cv; cv = cv->c_next)
533
cv->c_ye = i + hh - 1;
539
RethinkDisplayViewports();
540
ResizeLayersToCanvases();
548
struct canvas *cv, **cvpp;
551
h = D_height - (D_has_hstatus == HSTATUS_LASTLINE);
552
for (cv = D_cvlist, j = 0; cv; cv = cv->c_next)
558
for (cvpp = &D_cvlist; (cv = *cvpp); cvpp = &cv->c_next)
560
if (cv == D_forecv && !did)
565
D_forecv = cv ? cv : D_cvlist;
566
D_fore = Layer2Window(D_forecv->c_layer);
567
flayer = D_forecv->c_layer;
573
if (!captionalways && i == 0 && j == 0)
576
cv->c_ye = i + hh - 1;
581
RethinkDisplayViewports();
582
ResizeLayersToCanvases();
588
struct canvas *mycv = D_forecv;
589
struct canvas *cv, **cvpp;
591
for (cvpp = &D_cvlist; (cv = *cvpp);)
596
cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
606
RethinkDisplayViewports();
607
ResizeLayersToCanvases();
611
RethinkDisplayViewports()
614
struct viewport *vp, *vpn;
616
/* free old viewports */
617
for (cv = display->d_cvlist; cv; cv = cv->c_next)
619
for (vp = cv->c_vplist; vp; vp = vpn)
623
bzero((char *)vp, sizeof(*vp));
628
display->d_vpxmin = -1;
629
display->d_vpxmax = -1;
631
for (cv = display->d_cvlist; cv; cv = cv->c_next)
633
if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
638
vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
641
vp->v_xoff = cv->c_xoff;
642
vp->v_yoff = cv->c_yoff;
643
vp->v_next = cv->c_vplist;
646
if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
649
vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
650
vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
652
vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
653
vp->v_xoff = cv->c_xoff;
654
vp->v_yoff = cv->c_yoff;
655
vp->v_next = cv->c_vplist;
658
if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
662
vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
663
vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
664
vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
665
vp->v_xoff = cv->c_xoff;
666
vp->v_yoff = cv->c_yoff;
667
vp->v_next = cv->c_vplist;
670
if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
676
vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
677
vp->v_xoff = cv->c_xoff;
678
vp->v_yoff = cv->c_yoff;
679
vp->v_next = cv->c_vplist;
687
vp->v_xoff = cv->c_xoff;
688
vp->v_yoff = cv->c_yoff;
689
vp->v_next = cv->c_vplist;
693
if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
694
display->d_vpxmin = cv->c_xs;
695
if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
696
display->d_vpxmax = cv->c_xe;
702
RethinkViewportOffsets(cv)
707
for (vp = cv->c_vplist; vp; vp = vp->v_next)
709
vp->v_xoff = cv->c_xoff;
710
vp->v_yoff = cv->c_yoff;
715
* if the adaptflag is on, we keep the size of this display, else
716
* we may try to restore our old window sizes.
727
/* Check for toggle */
728
if (D_IM && strcmp(D_IM, D_EI))
735
/* Check for toggle */
736
if (D_KS && strcmp(D_KS, D_KE))
738
if (D_CCS && strcmp(D_CCS, D_CCE))
749
ResizeDisplay(D_defwidth, D_defheight);
750
ChangeScrollRegion(0, D_height - 1);
754
debug1("we %swant to adapt all our windows to the display\n",
755
(adapt) ? "" : "don't ");
756
/* In case the size was changed by a init sequence */
757
CheckScreenSize((adapt) ? 2 : 0);
769
ResizeDisplay(D_defwidth, D_defheight);
771
ChangeScrollRegion(0, D_height - 1);
776
SetRendition(&mchar_null);
783
ShowHStatus((char *)0);
788
GotoPos(0, D_height - 1);
802
if (!D_insert && D_x < D_width - 1)
816
RefreshLine(D_y, D_x, D_width-1, 0);
828
if (D_insert && D_x < D_width - 1)
837
if (D_x < D_width - 1)
844
if (D_CLP || D_y != D_bot)
849
GotoPos(D_width - 1, y);
852
debug("PUTCHARLP: lp_missing!\n");
857
/* XXX -> PutChar ? */
861
D_lpchar.image = D_mbcs;
869
* RAW_PUTCHAR() is for all text that will be displayed.
870
* NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
881
if (D_encoding == UTF8)
883
c = (c & 255) | (unsigned char)D_rend.font << 8;
889
D_x += D_AM ? 1 : -1;
892
else if (utf8_isdouble(c))
901
AddCStr2(D_CS0, '0');
911
if (is_dw_font(D_rend.font))
921
if (D_x == D_width - 1)
922
D_x += D_AM ? 1 : -1;
927
# if defined(ENCODINGS) && defined(DW_CHARS)
929
c = PrepareEncodedChar(c);
934
if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
935
AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
937
AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
945
if (++D_x >= D_width)
949
else if (!D_CLP || D_x > D_width)
952
if (D_y < D_height-1 && D_y != D_bot)
970
/* this is for ESC-sequences only (AddChar is a macro) */
979
if (display && s && *s)
982
tputs(s, 1, DoAddChar);
991
if (display && s && *s)
994
tputs(tgoto(s, 0, c), 1, DoAddChar);
999
/* Insert mode is a toggle on some terminals, so we need this hack:
1005
if (display && on != D_insert && D_IM)
1015
/* ...and maybe keypad application mode is a toggle, too:
1025
if (display && D_keypad != on && D_KS)
1044
if (display && D_cursorkeys != on && D_CCS)
1059
if (display && D_revvid != on && D_CVR)
1073
if (display && D_curvis != v)
1076
AddCStr(D_VE); /* do this always, just to be safe */
1078
if (v == -1 && D_VI)
1080
else if (v == 1 && D_VS)
1092
if (display && D_mouse != mode)
1099
sprintf(mousebuf, "\033[?%dl", D_mouse);
1104
sprintf(mousebuf, "\033[?%dh", mode);
1131
tputs(s, 1, CountChars);
1139
CallRewrite(y, xs, xe, doit)
1140
int y, xs, xe, doit;
1142
struct canvas *cv, *cvlist, *cvlnext;
1143
struct viewport *vp;
1144
struct layer *oldflayer;
1147
debug3("CallRewrite %d %d %d\n", y, xs, xe);
1152
for (cv = D_cvlist; cv; cv = cv->c_next)
1154
if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1156
for (vp = cv->c_vplist; vp; vp = vp->v_next)
1157
if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1165
flayer = cv->c_layer;
1166
cvlist = flayer->l_cvlist;
1167
cvlnext = cv->c_lnext;
1168
flayer->l_cvlist = cv;
1170
LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1171
flayer->l_cvlist = cvlist;
1172
cv->c_lnext = cvlnext;
1176
if (cv == 0 || cv->c_layer == 0)
1177
return EXPENSIVE; /* not found or nothing on it */
1178
if (xs < vp->v_xs || xe > vp->v_xe)
1179
return EXPENSIVE; /* crosses viewport boundaries */
1180
if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1181
return EXPENSIVE; /* line not on layer */
1182
if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1183
return EXPENSIVE; /* line not on layer */
1185
if (D_encoding == UTF8)
1189
flayer = cv->c_layer;
1190
debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1191
cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1194
cost += D_EIcost + D_IMcost;
1203
register int dy, dx, x1, y1;
1204
register int costx, costy;
1208
enum move_t xm = M_NONE, ym = M_NONE;
1219
x1 = -1; /* don't know how the terminal treats this */
1227
if (dy == 0 && dx == 0)
1229
debug2("GotoPos (%d,%d)", x1, y1);
1230
debug2(" -> (%d,%d)\n", x2, y2);
1231
if (!D_MS) /* Safe to move ? */
1232
SetRendition(&mchar_null);
1233
if (y1 < 0 /* don't know the y position */
1234
|| (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1235
|| (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1238
if (D_HO && !x2 && !y2)
1241
AddCStr(tgoto(D_CM, x2, y2));
1247
/* some scrollregion implementations don't allow movements
1248
* away from the region. sigh.
1250
if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1253
/* Calculate CMcost */
1254
if (D_HO && !x2 && !y2)
1257
s = tgoto(D_CM, x2, y2);
1258
CMcost = CalcCost(s);
1260
/* Calculate the cost to move the cursor to the right x position */
1262
if (x1 >= 0) /* relativ x positioning only if we know where we are */
1266
if (D_CRI && (dx > 1 || !D_ND))
1268
costx = CalcCost(tgoto(D_CRI, 0, dx));
1271
if ((m = D_NDcost * dx) < costx)
1276
/* Speedup: dx <= LayRewrite() */
1277
if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1285
if (D_CLE && (dx < -1 || !D_BC))
1287
costx = CalcCost(tgoto(D_CLE, 0, -dx));
1290
if ((m = -dx * D_LEcost) < costx)
1299
/* Speedup: LayRewrite() >= x2 */
1300
if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1306
/* Check if it is already cheaper to do CM */
1307
if (costx >= CMcost)
1310
/* Calculate the cost to move the cursor to the right y position */
1314
if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1316
costy = CalcCost(tgoto(D_CDO, 0, dy));
1319
if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1327
if (D_CUP && (dy < -1 || !D_UP))
1329
costy = CalcCost(tgoto(D_CUP, 0, -dy));
1332
if ((m = -dy * D_UPcost) < costy)
1341
/* Finally check if it is cheaper to do CM */
1342
if (costx + costy >= CMcost)
1352
AddCStr2(D_CLE, -dx);
1359
AddCStr2(D_CRI, dx);
1368
(void) CallRewrite(y1, x1, x2 - 1, 1);
1381
AddCStr2(D_CUP, -dy);
1384
s = (x2 == 0) ? D_NL : D_DO;
1389
AddCStr2(D_CDO, dy);
1402
ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1406
ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1407
int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1411
struct viewport *vp;
1413
debug2("Clear %d,%d", x1, y1);
1414
debug2(" %d-%d", xs, xe);
1415
debug2(" %d,%d", x2, y2);
1416
debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1426
if (D_UT) /* Safe to erase ? */
1427
SetRendition(&mchar_null);
1432
if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1434
if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1437
if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1440
if (x1 == 0 && y1 == 0 && D_auto_nuke)
1443
if (x1 == 0 && y1 == 0 && D_CL)
1450
* Workaround a hp700/22 terminal bug. Do not use CD where CE
1451
* is also appropriate.
1453
if (D_CD && (y1 < y2 || !D_CE))
1460
if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1467
for (y = y1; y <= y2; y++, x1 = xs)
1471
if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1477
if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1486
for (cv = D_cvlist; cv; cv = cv->c_next)
1488
if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1490
for (vp = cv->c_vplist; vp; vp = vp->v_next)
1491
if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1496
if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1497
y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1498
xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1500
struct layer *oldflayer = flayer;
1501
struct canvas *cvlist, *cvlnext;
1502
flayer = cv->c_layer;
1503
cvlist = flayer->l_cvlist;
1504
cvlnext = cv->c_lnext;
1505
flayer->l_cvlist = cv;
1507
LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1508
flayer->l_cvlist = cvlist;
1509
cv->c_lnext = cvlnext;
1514
ClearLine((struct mline *)0, y, x1, xxe, bce);
1520
* if cur_only > 0, we only redisplay current line, as a full refresh is
1521
* too expensive over a low baud line.
1529
/* XXX do em all? */
1531
ChangeScrollRegion(0, D_height - 1);
1534
CursorVisibility(0);
1536
SetRendition(&mchar_null);
1543
if (cur_only > 0 && D_fore)
1544
RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1548
CV_CALL(D_forecv, LayRestore();LaySetCursor());
1552
RedisplayDisplays(cur_only)
1555
struct display *olddisplay = display;
1556
for (display = displays; display; display = display->d_next)
1557
Redisplay(cur_only);
1558
display = olddisplay;
1564
ScrollH(y, xs, xe, n, bce, oml)
1565
int y, xs, xe, n, bce;
1572
if (xe != D_width - 1)
1574
RefreshLine(y, xs, xe, 0);
1575
/* UpdateLine(oml, y, xs, xe); */
1580
SetRendition(&mchar_null);
1587
if (n >= xe - xs + 1)
1589
if (D_CDC && !(n == 1 && D_DC))
1598
RefreshLine(y, xs, xe, 0);
1599
/* UpdateLine(oml, y, xs, xe); */
1605
if (-n >= xe - xs + 1)
1609
if (D_CIC && !(n == -1 && D_IC))
1610
AddCStr2(D_CIC, -n);
1619
SetRendition(&mchar_null);
1625
bce = 0; /* all done */
1629
/* UpdateLine(oml, y, xs, xe); */
1630
RefreshLine(y, xs, xe, 0);
1636
SetRendition(&mchar_null);
1642
bce = 0; /* all done */
1648
ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
1650
ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
1652
if (D_lp_missing && y == D_bot)
1655
WriteLP(D_width - 1 - n, y);
1661
ScrollV(xs, ys, xe, ye, n, bce)
1662
int xs, ys, xe, ye, n, bce;
1667
int alok, dlok, aldlfaster;
1673
if (n >= ye - ys + 1 || -n >= ye - ys + 1)
1675
ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
1678
if (xs > D_vpxmin || xe < D_vpxmax)
1680
RefreshArea(xs, ys, xe, ye, 0);
1686
if (D_bot > ye || D_bot < ys)
1691
if (missy > ye || missy < ys)
1702
if (n >= ye - ys + 1)
1707
if (ys < D_top || D_bot != ye)
1708
ChangeScrollRegion(ys, ye);
1709
alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
1710
dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
1711
if (D_top != ys && !(alok && dlok))
1712
ChangeScrollRegion(ys, ye);
1716
(oldbot == D_bot && up && D_top == ys && D_bot == ye)))
1718
WriteLP(D_width - 1, oldbot);
1719
if (oldbot == D_bot) /* have scrolled */
1724
ChangeScrollRegion(oldtop, oldbot);
1727
ClearLine((struct mline *)0, ye, xs, xe, bce);
1734
SetRendition(&mchar_null);
1740
aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
1742
if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
1747
for(i = n; i-- > 0; )
1748
AddCStr(D_NL); /* was SF, I think NL is faster */
1753
for(i = n; i-- > 0; )
1757
else if (alok && dlok)
1759
if (up || ye != D_bot)
1761
GotoPos(0, up ? ys : ye+1-n);
1762
if (D_CDL && !(n == 1 && D_DL))
1768
if (!up || ye != D_bot)
1770
GotoPos(0, up ? ye+1-n : ys);
1771
if (D_CAL && !(n == 1 && D_AL))
1780
RefreshArea(xs, ys, xe, ye, 0);
1786
ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
1788
ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
1790
if (D_lp_missing && missy != D_bot)
1791
WriteLP(D_width - 1, missy);
1793
ChangeScrollRegion(oldtop, oldbot);
1794
if (D_lp_missing && missy != D_bot)
1795
WriteLP(D_width - 1, missy);
1803
register int i, j, old, typ;
1805
if (!display || (old = D_rend.attr) == new)
1808
D_col16change = (old ^ new) & (A_BFG | A_BBG);
1809
new ^= D_col16change;
1813
#if defined(TERMINFO) && defined(USE_SGR)
1819
tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
1820
new & A_DI, new & A_BD, 0 , 0 ,
1826
rend_setdefault(&D_rend);
1833
if ((new & old) != old)
1843
/* ansi attrib handling: \E[m resets color, too */
1845
rend_setdefault(&D_rend);
1850
/* D_ME may also reset the alternate charset */
1862
for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
1869
AddCStr(D_attrtab[i]);
1870
typ |= D_attrtyp[i];
1881
int old = D_rend.font;
1882
if (!display || old == new)
1886
if (D_encoding && CanEncodeFont(D_encoding, new))
1888
if (new == D_realfont)
1892
if (D_xtable && D_xtable[(int)(unsigned char)new] &&
1893
D_xtable[(int)(unsigned char)new][256])
1895
AddCStr(D_xtable[(int)(unsigned char)new][256]);
1899
if (!D_CG0 && new != '0')
1918
AddCStr2(D_CS0, new);
1933
jj = (jj - 232) / 6;
1934
jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
1942
min = r < g ? (r < b ? r : b) : (g < b ? g : b);
1943
max = r > g ? (r > b ? r : b) : (g > b ? g : b);
1945
jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
1947
jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
1948
min) / (max - min) | (max > 3 ? 8 : 0);
1961
return (jj - 232) / 3 + 80;
1968
return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
1979
static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
1984
of = rend_getfg(&D_rend);
1985
ob = rend_getbg(&D_rend);
1988
/* intense default not invented yet */
1994
debug2("SetColor %d %d", coli2e(of), coli2e(ob));
1995
debug2(" -> %d %d\n", coli2e(f), coli2e(b));
1996
debug2("(%d %d", of, ob);
1997
debug2(" -> %d %d)\n", f, b);
1999
if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2006
oattr = D_rend.attr;
2007
AddCStr(D_ME ? D_ME : "\033[m");
2011
/* D_ME may also reset the alternate charset */
2024
rend_setfg(&D_rend, f);
2025
rend_setbg(&D_rend, b);
2031
f = f ? coli2e(f) : -1;
2032
b = b ? coli2e(b) : -1;
2033
of = of ? coli2e(of) : -1;
2034
ob = ob ? coli2e(ob) : -1;
2036
if (f != of && f > 15 && D_CCO != 256)
2037
f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2038
if (f != of && f > 15 && D_CAF)
2043
if (b != ob && b > 15 && D_CCO != 256)
2044
b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2045
if (b != ob && b > 15 && D_CAB)
2051
if (f != of && f != (of | 8))
2054
AddCStr("\033[39m"); /* works because AX is set */
2056
AddCStr2(D_CAF, f & 7);
2058
AddCStr2(D_CSF, sftrans[f & 7]);
2060
if (b != ob && b != (ob | 8))
2063
AddCStr("\033[49m"); /* works because AX is set */
2065
AddCStr2(D_CAB, b & 7);
2067
AddCStr2(D_CSB, sftrans[b & 7]);
2070
if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2073
AddCStr2("\033[9%p1%dm", f & 7);
2075
AddCStr2("\033[9%dm", f & 7);
2078
if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2081
AddCStr2("\033[10%p1%dm", b & 7);
2083
AddCStr2("\033[10%dm", b & 7);
2095
SetColor(rend_getfg(&D_rend), new);
2105
if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2107
static struct mchar mmc;
2110
for (i = 0; i < 8; i++)
2111
if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2113
if (mc->color == 0 && attr2color[i][3])
2114
ApplyAttrColor(attr2color[i][3], &mmc);
2115
else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2116
ApplyAttrColor(attr2color[i][2], &mmc);
2117
else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2118
ApplyAttrColor(attr2color[i][1], &mmc);
2120
ApplyAttrColor(attr2color[i][0], &mmc);
2123
debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2125
if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2128
if ((mc->attr & A_BFG) && D_MD)
2130
if ((mc->attr & A_BBG) && D_MB)
2132
if (D_rend.attr != a)
2135
else if (D_rend.attr != mc->attr)
2138
if (D_rend.color != mc->color
2140
|| D_rend.colorx != mc->colorx
2146
SetColor(rend_getfg(mc), rend_getbg(mc));
2149
if (D_rend.font != mc->font)
2155
SetRenditionMline(ml, x)
2161
if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2164
copy_mline2mchar(&mc, ml, x);
2168
if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2170
int a = ml->attr[x];
2171
if ((ml->attr[x] & A_BFG) && D_MD)
2173
if ((ml->attr[x] & A_BBG) && D_MB)
2175
if (D_rend.attr != a)
2178
else if (D_rend.attr != ml->attr[x])
2179
SetAttr(ml->attr[x]);
2181
if (D_rend.color != ml->color[x]
2183
|| D_rend.colorx != ml->colorx[x]
2191
copy_mline2mchar(&mc, ml, x);
2192
SetColor(rend_getfg(&mc), rend_getbg(&mc));
2196
if (D_rend.font != ml->font[x])
2197
SetFont(ml->font[x]);
2205
register char *s, *t;
2215
debug("tc not inited, just writing msg\n");
2216
if (D_processinputdata)
2217
return; /* XXX: better */
2223
if (!use_hardstatus || !D_HS)
2230
max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2234
if (strcmp(msg, D_status_lastmsg) == 0)
2236
debug("same message - increase timeout");
2237
SetTimeout(&D_statusev, MsgWait);
2244
gettimeofday(&now, NULL);
2245
ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2246
if (ti < MsgMinWait)
2247
DisplaySleep1000(MsgMinWait - ti, 0);
2251
for (s = t = msg; *s && t - msg < max; ++s)
2254
else if ((unsigned char)*s >= ' ' && *s != 0177)
2259
if (t - msg >= D_status_buflen)
2262
if (D_status_lastmsg)
2263
buf = realloc(D_status_lastmsg, t - msg + 1);
2265
buf = malloc(t - msg + 1);
2268
D_status_lastmsg = buf;
2269
D_status_buflen = t - msg + 1;
2272
if (t - msg < D_status_buflen)
2273
strcpy(D_status_lastmsg, msg);
2274
D_status_len = t - msg;
2275
D_status_lastx = D_x;
2276
D_status_lasty = D_y;
2277
if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2279
D_status = STATUS_ON_WIN;
2280
debug1("using STATLINE %d\n", STATLINE);
2281
GotoPos(0, STATLINE);
2282
SetRendition(&mchar_so);
2285
if (D_status_len < max)
2287
/* Wayne Davison: add extra space for readability */
2289
SetRendition(&mchar_null);
2291
if (D_status_len < max)
2303
D_status = STATUS_ON_HS;
2309
if (D_status == STATUS_ON_WIN)
2311
struct display *olddisplay = display;
2312
struct layer *oldflayer = flayer;
2314
ASSERT(D_obuffree == D_obuflen);
2315
/* this is copied over from RemoveStatus() */
2317
GotoPos(0, STATLINE);
2318
RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2319
GotoPos(D_status_lastx, D_status_lasty);
2320
flayer = D_forecv ? D_forecv->c_layer : 0;
2323
display = olddisplay;
2325
D_status_obuflen = D_obuflen;
2326
D_status_obuffree = D_obuffree;
2327
D_obuffree = D_obuflen = 0;
2328
D_status = STATUS_ON_WIN;
2330
gettimeofday(&D_status_time, NULL);
2331
SetTimeout(&D_statusev, MsgWait);
2334
RefreshBraille(); /* let user see multiple Msg()s */
2341
struct display *olddisplay;
2342
struct layer *oldflayer;
2347
if (!(where = D_status))
2350
debug("RemoveStatus\n");
2351
if (D_status_obuffree >= 0)
2353
D_obuflen = D_status_obuflen;
2354
D_obuffree = D_status_obuffree;
2355
D_status_obuffree = -1;
2364
olddisplay = display;
2366
if (where == STATUS_ON_WIN)
2368
GotoPos(0, STATLINE);
2369
RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2370
GotoPos(D_status_lastx, D_status_lasty);
2374
flayer = D_forecv ? D_forecv->c_layer : 0;
2377
display = olddisplay;
2381
/* refresh the display's hstatus line */
2386
int l, i, ox, oy, max;
2388
if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2389
return; /* sorry, in use */
2393
if (D_HS && D_has_hstatus == HSTATUS_HS)
2395
if (!D_hstatus && (str == 0 || *str == 0))
2397
debug("ShowHStatus: using HS\n");
2398
SetRendition(&mchar_null);
2403
if (str == 0 || *str == 0)
2406
max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2407
if ((int)strlen(str) > max)
2414
else if (D_has_hstatus == HSTATUS_LASTLINE)
2416
debug("ShowHStatus: using last line\n");
2419
str = str ? str : "";
2423
GotoPos(0, D_height - 1);
2424
SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2425
if (!PutWinMsg(str, 0, l))
2426
for (i = 0; i < l; i++)
2428
if (!captionalways && D_cvlist && !D_cvlist->c_next)
2429
while (l++ < D_width)
2432
ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2433
if (ox != -1 && oy != -1)
2435
D_hstatus = *str ? 1 : 0;
2436
SetRendition(&mchar_null);
2438
else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2440
debug("ShowHStatus: using message\n");
2447
* Refreshes the harstatus of the fore window. Shouldn't be here...
2454
evdeq(&D_hstatusev);
2455
if (D_status == STATUS_ON_HS)
2457
buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2461
if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2462
evenq(&D_hstatusev);
2465
ShowHStatus((char *)0);
2468
/*********************************************************************/
2470
* Here come the routines that refresh an arbitrary part of the screen.
2480
debug("Signalling full refresh!\n");
2481
for (cv = D_cvlist; cv; cv = cv->c_next)
2483
CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2484
display = cv->c_display; /* just in case! */
2486
RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2490
RefreshArea(xs, ys, xe, ye, isblank)
2491
int xs, ys, xe, ye, isblank;
2495
debug2("Refresh Area: %d,%d", xs, ys);
2496
debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2497
if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2499
ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2502
for (y = ys; y <= ye; y++)
2503
RefreshLine(y, xs, xe, isblank);
2507
RefreshLine(y, from, to, isblank)
2508
int y, from, to, isblank;
2510
struct viewport *vp, *lvp;
2511
struct canvas *cv, *lcv, *cvlist, *cvlnext;
2512
struct layer *oldflayer;
2519
debug2("RefreshLine %d %d", y, from);
2520
debug2(" %d %d\n", to, isblank);
2522
if (D_status == STATUS_ON_WIN && y == STATLINE)
2523
return; /* can't refresh status */
2525
if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2529
SetRendition(&mchar_null);
2537
for (cv = display->d_cvlist; cv; cv = cv->c_next)
2539
if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
2541
debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
2542
debug2(" %d %d\n", cv->c_xe, cv->c_ye);
2543
for (vp = cv->c_vplist; vp; vp = vp->v_next)
2545
debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
2546
debug2(" %d %d\n", vp->v_xe, vp->v_ye);
2547
/* find leftmost overlapping vp */
2548
if (y >= vp->v_ys && y <= vp->v_ye && from <= vp->v_xe && to >= vp->v_xs && (lvp == 0 || lvp->v_xs > vp->v_xs))
2557
if (from < lvp->v_xs)
2560
DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
2564
/* call LayRedisplayLine on canvas lcv viewport lvp */
2565
yy = y - lvp->v_yoff;
2566
xx = to < lvp->v_xe ? to : lvp->v_xe;
2568
if (lcv->c_layer && yy == lcv->c_layer->l_height)
2571
SetRendition(&mchar_blank);
2572
while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
2577
if (from >= lvp->v_xe + 1)
2580
if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
2583
DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
2584
from = lvp->v_xe + 1;
2588
if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
2589
xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
2591
flayer = lcv->c_layer;
2592
cvlist = flayer->l_cvlist;
2593
cvlnext = lcv->c_lnext;
2594
flayer->l_cvlist = lcv;
2596
LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
2597
flayer->l_cvlist = cvlist;
2598
lcv->c_lnext = cvlnext;
2604
return; /* all done */
2606
if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2612
for (cv = display->d_cvlist; cv; cv = cv->c_next)
2613
if (y == cv->c_ye + 1)
2618
DisplayLine(&mline_null, &mline_blank, y, from, to);
2622
p = Layer2Window(cv->c_layer);
2623
buf = MakeWinMsgEv(captionstring, p, '%', D_width - !D_CLP, &cv->c_captev, 0);
2624
if (cv->c_captev.timeout.tv_sec)
2625
evenq(&cv->c_captev);
2628
SetRendition(&mchar_so);
2629
if (PutWinMsg(buf, from, to + 1))
2630
from = xx > to + 1 ? to + 1 : xx;
2633
while (from <= to && from < xx)
2635
PUTCHARLP(buf[from]);
2639
while (from++ <= to)
2643
/*********************************************************************/
2645
/* clear lp_missing by writing the char on the screen. The
2646
* position must be safe.
2652
struct mchar oldrend;
2655
ASSERT(D_lp_missing);
2657
debug2("WriteLP(%d,%d)\n", x2, y2);
2664
D_lpchar = mchar_blank;
2667
/* Can't use PutChar */
2669
SetRendition(&D_lpchar);
2670
PUTCHAR(D_lpchar.image);
2673
PUTCHAR(D_lpchar.mbcs);
2676
SetRendition(&oldrend);
2680
ClearLine(oml, y, from, to, bce)
2682
int from, to, y, bce;
2686
struct mchar bcechar;
2689
debug3("ClearLine %d,%d-%d\n", y, from, to);
2690
if (D_UT) /* Safe to erase ? */
2691
SetRendition(&mchar_null);
2696
if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
2702
if (to == D_width - 1 && D_CE && (!bce || D_BE))
2713
DisplayLine(oml, &mline_blank, y, from, to);
2716
bcechar = mchar_blank;
2717
rend_setbg(&bcechar, bce);
2718
for (x = from; x <= to; x++)
2719
copy_mchar2mline(&bcechar, &mline_old, x);
2720
DisplayLine(oml, &mline_old, y, from, to);
2722
DisplayLine(oml, &mline_blank, y, from, to);
2727
DisplayLine(oml, ml, y, from, to)
2728
struct mline *oml, *ml;
2732
int last2flag = 0, delete_lp = 0;
2735
ASSERT(y >= 0 && y < D_height);
2736
ASSERT(from >= 0 && from < D_width);
2737
ASSERT(to >= 0 && to < D_width);
2738
if (!D_CLP && y == D_bot && to == D_width - 1)
2740
if (D_lp_missing || !cmp_mline(oml, ml, to))
2743
if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
2745
if ((D_IC || D_IM) && from < to)
2754
delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
2755
D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
2756
copy_mline2mchar(&D_lpchar, ml, to);
2764
/* finish dw-char (can happen after a wrap) */
2765
debug("DisplayLine finishing kanji\n");
2766
SetRenditionMline(ml, from);
2767
PUTCHAR(ml->image[from]);
2771
for (x = from; x <= to; x++)
2773
#if 0 /* no longer needed */
2774
if (x || D_x != D_width || D_y != y - 1)
2777
if (x < to || x != D_width - 1 || ml->image[x + 1])
2778
if (cmp_mline(oml, ml, x))
2783
if (dw_right(ml, x, D_encoding))
2786
debug1("DisplayLine on right side of dw char- x now %d\n", x);
2789
if (x == to && dw_left(ml, x, D_encoding))
2790
break; /* don't start new kanji */
2792
SetRenditionMline(ml, x);
2793
PUTCHAR(ml->image[x]);
2795
if (dw_left(ml, x, D_encoding))
2796
PUTCHAR(ml->image[++x]);
2799
#if 0 /* not needed any longer */
2800
/* compare != 0 because ' ' can happen when clipping occures */
2801
if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
2807
SetRenditionMline(ml, x + 1);
2808
PUTCHAR(ml->image[x + 1]);
2810
SetRenditionMline(ml, x);
2811
INSERTCHAR(ml->image[x]);
2816
SetRendition(&mchar_null);
2833
PUTCHARLP(c->image);
2838
if (D_encoding == UTF8)
2847
InsChar(c, x, xe, y, oml)
2853
if (y == D_bot && !D_CLP)
2855
if (x == D_width - 1)
2861
if (xe == D_width - 1)
2867
PUTCHARLP(c->image);
2870
if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
2872
RefreshLine(y, x, xe, 0);
2874
/* UpdateLine(oml, y, x, xe); */
2881
if (c->mbcs && D_IC)
2886
AddCStr2(D_CIC, c->mbcs ? 2 : 1);
2895
RAW_PUTCHAR(c->image);
2900
if (D_encoding == UTF8)
2903
if (D_x == D_width - 1)
2906
RAW_PUTCHAR(c->mbcs);
2912
WrapChar(c, x, y, xs, ys, xe, ye, ins)
2921
bce = rend_getbg(c);
2926
debug2(" x %d y %d", x, y);
2927
debug2(" Dx %d Dy %d", D_x, D_y);
2928
debug2(" xs %d ys %d", xs, ys);
2929
debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
2930
if (xs != 0 || x != D_width || !D_AM)
2933
ScrollV(xs, ys, xe, ye, 1, bce);
2934
else if (y < D_height - 1)
2937
InsChar(c, xs, xe, y, 0);
2942
if (y == ye) /* we have to scroll */
2944
debug("- scrolling\n");
2945
ChangeScrollRegion(ys, ye);
2946
if (D_bot != y || D_x != D_width || (!bce && !D_BE))
2948
debug("- have to call ScrollV\n");
2949
ScrollV(xs, ys, xe, ye, 1, bce);
2953
else if (y == D_bot) /* remove unusable region? */
2954
ChangeScrollRegion(0, D_height - 1);
2955
if (D_x != D_width || D_y != y)
2957
if (D_CLP && y >= 0) /* don't even try if !LP */
2958
RefreshLine(y, D_width - 1, D_width - 1, 0);
2959
debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
2960
if (D_x != D_width || D_y != y) /* sorry, no bonus */
2963
ScrollV(xs, ys, xe, ye, 1, bce);
2964
GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
2967
debug("- writeing new char");
2968
if (y != ye && y < D_height - 1)
2970
if (ins != D_insert)
2972
if (ins && !D_insert)
2974
InsChar(c, 0, xe, y, 0);
2975
debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
2981
RAW_PUTCHAR(c->image);
2986
if (D_encoding == UTF8)
2989
RAW_PUTCHAR(c->mbcs);
2992
debug2(" -> done (%d,%d)\n", D_x, D_y);
2996
ResizeDisplay(wi, he)
3000
debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3001
if (D_width == wi && D_height == he)
3003
debug("ResizeDisplay: No change\n");
3006
if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3008
debug("ResizeDisplay: using Z0/Z1\n");
3009
AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3010
ChangeScreenSize(wi, D_height, 0);
3011
return (he == D_height) ? 0 : -1;
3015
debug("ResizeDisplay: using WS\n");
3016
AddCStr(tgoto(D_CWS, wi, he));
3017
ChangeScreenSize(wi, he, 0);
3024
ChangeScrollRegion(newtop, newbot)
3029
if (newtop == newbot)
3030
return; /* xterm etc can't do it */
3034
newbot = D_height - 1;
3038
D_bot = D_height - 1;
3041
if (D_top == newtop && D_bot == newbot)
3043
debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3044
AddCStr(tgoto(D_CS, newbot, newtop));
3047
D_y = D_x = -1; /* Just in case... */
3056
static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3063
if (!D_xtermosc[i] && !*s)
3066
s = "screen"; /* always set icon name */
3068
s = ""; /* no background */
3070
s = "black"; /* black text */
3072
s = "white"; /* on white background */
3075
AddStr(oscs + i * 4);
3084
for (i = 3; i >= 0; i--)
3090
* Output buffering routines
3102
if (D_encoding == UTF8)
3104
while ((c = *str++))
3105
AddUtf8((unsigned char)c);
3109
while ((c = *str++))
3122
if (D_encoding == UTF8)
3124
while ((c = *str++) && n-- > 0)
3125
AddUtf8((unsigned char)c);
3129
while ((c = *str++) && n-- > 0)
3142
l = D_obufp - D_obuf;
3143
debug1("Flush(): %d\n", l);
3146
ASSERT(l + D_obuffree == D_obuflen);
3154
if (fcntl(D_userfd, F_SETFL, 0))
3155
debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3159
wr = write(D_userfd, p, l);
3164
debug1("Writing to display: %d\n", errno);
3175
if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3176
debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3187
debug1("did freetty %d\n", D_userfd);
3195
D_obuflenmax = -D_obufmax;
3201
* Asynchronous output routines by
3202
* Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3211
if (D_status_obuffree >= 0)
3213
ASSERT(D_obuffree == -1);
3218
gettimeofday(&now, NULL);
3219
ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3220
if (ti < MsgMinWait)
3221
DisplaySleep1000(MsgMinWait - ti, 0);
3224
if (--D_obuffree > 0) /* redo AddChar decrement */
3227
if (D_obuflen && D_obuf)
3229
ind = D_obufp - D_obuf;
3231
D_obuffree += GRAIN;
3232
D_obuf = realloc(D_obuf, D_obuflen);
3239
D_obuf = malloc(D_obuflen);
3242
Panic(0, "Out of memory");
3243
D_obufp = D_obuf + ind;
3244
D_obuflenmax = D_obuflen - D_obufmax;
3245
debug1("ResizeObuf: resized to %d\n", D_obuflen);
3249
DisplaySleep1000(n, eat)
3261
debug("DisplaySleep has no display sigh\n");
3265
t.tv_usec = (n % 1000) * 1000;
3266
t.tv_sec = n / 1000;
3268
FD_SET(D_userfd, &r);
3269
if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3271
debug("display activity stopped sleep\n");
3273
read(D_userfd, &buf, 1);
3275
debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3281
{/* Nuke pending output in current display, clear screen */
3283
int oldtop = D_top, oldbot = D_bot;
3284
struct mchar oldrend;
3285
int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3286
int oldcurvis = D_curvis;
3287
int oldmouse = D_mouse;
3290
len = D_obufp - D_obuf;
3291
debug1("NukePending: nuking %d chars\n", len);
3293
/* Throw away any output that we can... */
3295
tcflush(D_userfd, TCOFLUSH);
3298
(void) ioctl(D_userfd, TCFLSH, (char *) 1);
3307
/* Turn off all attributes. (Tim MacKenzie) */
3314
AddStr("\033[m"); /* why is D_ME not set? */
3319
/* Check for toggle */
3320
if (D_IM && strcmp(D_IM, D_EI))
3323
/* Check for toggle */
3325
if (D_KS && strcmp(D_KS, D_KE))
3327
if (D_CCS && strcmp(D_CCS, D_CCE))
3330
if (D_KS && strcmp(D_KS, D_KE))
3333
if (D_CCS && strcmp(D_CCS, D_CCE))
3338
D_rend = mchar_null;
3344
ChangeScrollRegion(oldtop, oldbot);
3345
SetRendition(&oldrend);
3346
KeypadMode(oldkeypad);
3347
CursorkeysMode(oldcursorkeys);
3348
CursorVisibility(oldcurvis);
3349
MouseMode(oldmouse);
3352
debug("ResizeDisplay: using WS\n");
3353
AddCStr(tgoto(D_CWS, D_width, D_height));
3355
else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3357
debug("ResizeDisplay: using Z0/Z1\n");
3358
AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3361
#endif /* AUTO_NUKE */
3364
/* linux' select can't handle flow control, so wait 100ms if
3368
disp_writeev_eagain(ev, data)
3372
display = (struct display *)data;
3374
D_writeev.type = EV_WRITE;
3375
D_writeev.handler = disp_writeev_fn;
3381
disp_writeev_fn(ev, data)
3385
int len, size = OUTPUT_BLOCK_SIZE;
3387
display = (struct display *)data;
3388
len = D_obufp - D_obuf;
3392
size = write(D_userfd, D_obuf, size);
3398
bcopy(D_obuf + size, D_obuf, len);
3399
debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3405
D_blocked_fuzz -= size;
3406
if (D_blocked_fuzz < 0)
3409
if (D_blockedev.queued)
3411
if (D_obufp - D_obuf > D_obufmax / 2)
3413
debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3414
SetTimeout(&D_blockedev, D_nonblock);
3418
debug1("%s: deleting blocked timeout\n", D_usertty);
3419
evdeq(&D_blockedev);
3422
if (D_blocked == 1 && D_obuf == D_obufp)
3424
/* empty again, restart output */
3425
debug1("%s: buffer empty, unblocking\n", D_usertty);
3427
Activate(D_fore ? D_fore->w_norefresh : 0);
3428
D_blocked_fuzz = D_obufp - D_obuf;
3434
/* linux flow control is badly broken */
3435
if (errno == EAGAIN)
3438
D_writeev.type = EV_TIMEOUT;
3439
D_writeev.handler = disp_writeev_eagain;
3440
SetTimeout(&D_writeev, 100);
3444
if (errno != EINTR && errno != EAGAIN)
3445
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3446
if (errno != EWOULDBLOCK)
3448
Msg(errno, "Error writing output to display");
3453
disp_readev_fn(ev, data)
3461
display = (struct display *)data;
3463
/* Hmmmm... a bit ugly... */
3465
for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3467
display = cv->c_display;
3468
if (D_status == STATUS_ON_WIN)
3472
display = (struct display *)data;
3479
size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3482
size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3488
size = 1; /* Always allow one char for command keys */
3490
size = read(D_userfd, buf, size);
3493
if (errno == EINTR || errno == EAGAIN)
3495
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3496
if (errno == EWOULDBLOCK)
3499
debug1("Read error: %d - hangup!\n", errno);
3506
debug("Found EOF - hangup!\n");
3517
Activate(D_fore ? D_fore->w_norefresh : 0);
3522
if (D_blocked > 1) /* 2, 3 */
3528
for (p = windows; p ; p = p->w_next)
3529
if (p->w_zdisplay == display)
3531
flayer = &p->w_layer;
3534
LayProcess(&bufp, &size);
3537
debug("zmodem window gone, deblocking display");
3538
zmodem_abort(0, display);
3544
D_fore->w_lastdisp = display;
3545
if (D_mouse && D_forecv)
3547
unsigned char *bp = (unsigned char *)buf;
3550
/* XXX this assumes that the string is read in as a whole... */
3551
for (i = size; i > 0; i--, bp++)
3553
if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3558
else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3562
if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
3564
x -= D_forecv->c_xoff;
3565
y -= D_forecv->c_yoff;
3566
if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
3577
bcopy((char *)bp + 1, (char *)bp, i);
3582
bcopy((char *)bp + 5, (char *)bp, i - 5);
3589
if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
3592
char buf2[IOSIZE * 2 + 10];
3593
enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
3594
for (i = j = 0; i < size; i++)
3596
c = ((unsigned char *)buf)[i];
3597
c = DecodeChar(c, D_encoding, &D_decodestate);
3599
i--; /* try char again */
3605
j += EncodeChar(buf2 + j, c, enc, &font);
3606
j += EncodeChar(buf2 + j, -1, enc, &font);
3609
j += EncodeChar(buf2 + j, c, enc, 0);
3610
if (j > (int)sizeof(buf2) - 10) /* just in case... */
3613
(*D_processinput)(buf2, j);
3617
(*D_processinput)(buf, size);
3621
disp_status_fn(ev, data)
3625
display = (struct display *)data;
3626
debug1("disp_status_fn for display %x\n", (int)display);
3632
disp_hstatus_fn(ev, data)
3636
display = (struct display *)data;
3637
if (D_status == STATUS_ON_HS)
3647
disp_blocked_fn(ev, data)
3653
display = (struct display *)data;
3654
debug1("blocked timeout %s\n", D_usertty);
3655
if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
3657
debug("stopping output to display\n");
3659
/* re-enable all windows */
3660
for (p = windows; p; p = p->w_next)
3661
if (p->w_readev.condneg == &D_obuflenmax)
3663
debug1("freeing window #%d\n", p->w_number);
3664
p->w_readev.condpos = p->w_readev.condneg = 0;
3670
cv_winid_fn(ev, data)
3675
struct canvas *cv = (struct canvas *)data;
3677
display = cv->c_display;
3678
if (D_status == STATUS_ON_WIN)
3686
if (cv->c_ye + 1 < D_height)
3687
RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
3688
if (ox != -1 && oy != -1)
3694
disp_map_fn(ev, data)
3701
display = (struct display *)data;
3702
debug("Flushing map sequence\n");
3705
p = (char *)D_seqp - l;
3706
D_seqp = D_kmaps + 3;
3708
if ((q = D_seqh) != 0)
3711
i = q[0] << 8 | q[1];
3712
i &= ~KMAP_NOTIMEOUT;
3713
debug1("Mapping former hit #%d - ", i);
3714
debug2("%d(%s) - ", q[2], q + 3);
3716
ProcessInput2((char *)q + 3, q[2]);
3729
disp_idle_fn(ev, data)
3733
struct display *olddisplay;
3734
display = (struct display *)data;
3735
debug("idle timeout\n");
3736
if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
3738
olddisplay = display;
3739
flayer = D_forecv->c_layer;
3741
DoAction(&idleaction, -1);
3742
if (idleaction.nr == RC_BLANKER)
3744
for (display = displays; display; display = display->d_next)
3745
if (olddisplay == display)
3756
SetTimeout(&D_idleev, idletimo);
3757
if (!D_idleev.queued)
3768
disp_blanker_fn(ev, data)
3772
char buf[IOSIZE], *b;
3775
display = (struct display *)data;
3776
size = read(D_blankerev.fd, buf, IOSIZE);
3779
evdeq(&D_blankerev);
3780
close(D_blankerev.fd);
3781
D_blankerev.fd = -1;
3784
for (b = buf; size; size--)
3791
int oldtop = D_top, oldbot = D_bot;
3792
struct mchar oldrend;
3794
if (D_blankerev.fd == -1)
3798
evdeq(&D_blankerev);
3799
close(D_blankerev.fd);
3800
D_blankerev.fd = -1;
3801
Kill(D_blankerpid, SIGHUP);
3813
AddStr("\033[m\033[m"); /* why is D_ME not set? */
3820
D_rend = mchar_null;
3824
ChangeScrollRegion(oldtop, oldbot);
3825
SetRendition(&oldrend);
3838
char libuf[20], cobuf[20];
3842
strcpy(termname, "TERM=");
3843
strncpy(termname + 5, D_termname, sizeof(termname) - 6);
3844
termname[sizeof(termname) - 1] = 0;
3847
if ((D_blankerev.fd = OpenPTY(&m)) == -1)
3849
Msg(0, "OpenPty failed");
3855
if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
3857
Msg(errno, "%s", m);
3858
close(D_blankerev.fd);
3859
D_blankerev.fd = -1;
3864
switch (pid = (int)fork())
3868
close(D_blankerev.fd);
3869
D_blankerev.fd = -1;
3874
if (dfp && dfp != stderr)
3877
if (setgid(real_gid) || setuid(real_uid))
3878
Panic(errno, "setuid/setgid");
3884
closeallfiles(slave);
3885
if (open(m, O_RDWR))
3886
Panic(errno, "Cannot open %s", m);
3893
SetTTY(0, &D_OldMode);
3898
glwz.ws_col = D_width;
3899
glwz.ws_row = D_height;
3900
(void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
3902
sprintf(libuf, "LINES=%d", D_height);
3903
sprintf(libuf, "COLUMNS=%d", D_width);
3908
signal(SIGPIPE, SIG_DFL);
3911
execvpe(*cmdv, cmdv, NewEnv + 3);
3912
Panic(errno, *cmdv);
3917
evenq(&D_blankerev);