1/* $XTermId: testxmc.c,v 1.55 2024/12/01 20:27:00 tom Exp $ */ 2 3/* 4 * Copyright 1997-2020,2024 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 92void 93Mark_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 == NULL) { 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 */ 162void 163Jump_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 */ 177void 178Resolve_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