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