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