1 /* $XTermId: testxmc.c,v 1.54 2020/11/08 20:12:21 tom Exp $ */
2
3 /*
4 * Copyright 1997-2019,2020 by Thomas E. Dickey
5 *
6 * All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 */
32
33 /*
34 * This module provides test support for curses applications that must work
35 * with terminals that have the xmc (magic cookie) glitch. The xmc_glitch
36 * resource denotes the number of spaces that are emitted when switching to or
37 * from standout (reverse) mode. Some terminals implement this by storing the
38 * attribute controls in the character cell that is skipped. So if the cell is
39 * overwritten by text, then the attribute change in the cell is cancelled,
40 * causing attributes to the left of the change to propagate.
41 *
42 * We implement the glitch by writing a character that won't be mistaken for
43 * other normal characters (and mapping normal writes to that character to a
44 * different one).
45 *
46 * Since xmc isn't normally part of xterm, we document it here rather than in
47 * the man-page. This module is driven by resources rather than by the
48 * termcap/terminfo description to make it a little more flexible for testing
49 * purposes.
50 *
51 * Resources:
52 *
53 * xmcGlitch (class XmcGlitch)
54 * When true, enables this extension. The default is `0', which disables
55 * the module. (termcap sg, terminfo xmc).
56 *
57 * xmcAttributes (class XmcAttributes)
58 * The attributes for which we'll generate a glitch, as a bitmask.
59 *
60 * INVERSE 1
61 * UNDERLINE 2
62 * BOLD 4
63 * BLINK 8
64 *
65 * The default is `1' (INVERSE). Some terminals emit glitches for
66 * underline. Just for completeness, we recognize all of the video
67 * attributes.
68 *
69 * xmcInline (class XmcInline)
70 * When true, limits the extent of an SGR change to the current line.
71 * The default is `false'. (No termcap or terminfo equivalent, though
72 * there are comments in some entries relating to this issue).
73 *
74 * xmcMoveSGR (class XmcMoveSGR)
75 * When false, a cursor movement will leave a glitch when SGR's are
76 * active. The default is `true'. (termcap ms, terminfo msgr).
77 *
78 * TODO:
79 * When xmc is active, the terminfo max_attributes (ma) capability is
80 * assumed to be 1.
81 *
82 * The xmcAttributes resource should also apply to alternate character
83 * sets and to color.
84 */
85
86 #include <xterm.h>
87 #include <data.h>
88
89 #define MARK_ON(a) (Bool) ((my_attrs & a) != 0 && (xw->flags & (whichone = CharOf(a))) == 0)
90 #define MARK_OFF(a) (Bool) ((my_attrs & a) != 0 && (xw->flags & (whichone = CharOf(a))) != 0)
91
92 void
Mark_XMC(XtermWidget xw,int param)93 Mark_XMC(XtermWidget xw, int param)
94 {
95 static IChar *glitch;
96
97 TScreen *screen = TScreenOf(xw);
98 Bool found = False;
99 unsigned my_attrs = CharOf(screen->xmc_attributes & XMC_FLAGS);
100 unsigned whichone = 0;
101
102 if (glitch == 0) {
103 unsigned len = screen->xmc_glitch;
104 glitch = TypeMallocN(IChar, len);
105 if (glitch == NULL) {
106 xtermWarning("Not enough core for xmc glitch mode\n");
107 return;
108 } else {
109 while (len--)
110 glitch[len] = XMC_GLITCH;
111 }
112 }
113 switch (param) {
114 case -1: /* DEFAULT */
115 case 0: /* FALLTHRU */
116 found = MARK_OFF((xw->flags & XMC_FLAGS));
117 break;
118 case 1:
119 found = MARK_ON(BOLD);
120 break;
121 case 4:
122 found = MARK_ON(UNDERLINE);
123 break;
124 case 5:
125 found = MARK_ON(BLINK);
126 break;
127 case 7:
128 found = MARK_ON(INVERSE);
129 break;
130 case 22:
131 found = MARK_OFF(BOLD);
132 break;
133 case 24:
134 found = MARK_OFF(UNDERLINE);
135 break;
136 case 25:
137 found = MARK_OFF(BLINK);
138 break;
139 case 27:
140 found = MARK_OFF(INVERSE);
141 break;
142 }
143
144 /*
145 * Write a glitch with the attributes temporarily set to the new(er)
146 * ones.
147 */
148 if (found) {
149 unsigned save = xw->flags;
150 xw->flags ^= whichone;
151 TRACE(("XMC Writing glitch (%d/%d) after SGR %d\n", my_attrs,
152 whichone, param));
153 dotext(xw, (DECNRCM_codes) '?', glitch, screen->xmc_glitch);
154 xw->flags = save;
155 }
156 }
157
158 /*
159 * Force a glitch on cursor movement when we're in standout mode and not at the
160 * end of a line.
161 */
162 void
Jump_XMC(XtermWidget xw)163 Jump_XMC(XtermWidget xw)
164 {
165 TScreen *screen = TScreenOf(xw);
166 if (!screen->move_sgr_ok
167 && screen->cur_col <= LineMaxCol(screen,
168 getLineData(screen, screen->cur_row))) {
169 Mark_XMC(xw, -1);
170 }
171 }
172
173 /*
174 * After writing text to the screen, resolve mismatch between the current
175 * location and any attributes that would have been set by preceding locations.
176 */
177 void
Resolve_XMC(XtermWidget xw)178 Resolve_XMC(XtermWidget xw)
179 {
180 TScreen *screen = TScreenOf(xw);
181 LineData *ld;
182 Bool changed = False;
183 IAttr start;
184 IAttr my_attrs = CharOf(screen->xmc_attributes & XMC_FLAGS);
185 int row = screen->cur_row;
186 int col = screen->cur_col;
187
188 /* Find the preceding cell.
189 */
190 ld = getLineData(screen, row);
191 if (ld->charData[col] != XMC_GLITCH) {
192 if (col != 0) {
193 col--;
194 } else if (!screen->xmc_inline && row != 0) {
195 ld = getLineData(screen, --row);
196 col = LineMaxCol(screen, ld);
197 }
198 }
199 start = (ld->attribs[col] & my_attrs);
200
201 /* Now propagate the starting state until we reach a cell which holds
202 * a glitch.
203 */
204 for (;;) {
205 if (col < LineMaxCol(screen, ld)) {
206 col++;
207 } else if (!screen->xmc_inline && row < screen->max_row) {
208 col = 0;
209 ld = getLineData(screen, ++row);
210 } else
211 break;
212 if (ld->charData[col] == XMC_GLITCH)
213 break;
214 if ((ld->attribs[col] & my_attrs) != start) {
215 ld->attribs[col] =
216 (IAttr) (start | (ld->attribs[col] & ~my_attrs));
217 changed = True;
218 }
219 }
220
221 TRACE(("XMC %s (%s:%d/%d) from %d,%d to %d,%d\n",
222 changed ? "Ripple" : "Nochange",
223 BtoS(xw->flags & my_attrs),
224 my_attrs, start,
225 screen->cur_row, screen->cur_col,
226 row, col));
227
228 if (changed) {
229 ScrnUpdate(xw, screen->cur_row, 0, row + 1 - screen->cur_row,
230 MaxCols(screen), True);
231 }
232 }
233