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