doublechr.c revision 2e4f8982
1/* $XTermId: doublechr.c,v 1.86 2016/05/17 08:33:58 tom Exp $ */ 2 3/* 4 * Copyright 1997-2014,2016 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#include <xterm.h> 34#include <data.h> 35#include <fontutils.h> 36 37#include <assert.h> 38 39#define WhichCgsId(flag) (((flag) & BOLD) ? gcCBold : gcCNorm) 40 41/* 42 * The first column is all that matters for double-size characters (since the 43 * controls apply to a whole line). However, it's easier to maintain the 44 * information for special fonts by writing to all cells. 45 */ 46#if OPT_DEC_CHRSET 47 48static void 49repaint_line(XtermWidget xw, unsigned newChrSet) 50{ 51 TScreen *screen = TScreenOf(xw); 52 LineData *ld; 53 int curcol = screen->cur_col; 54 int currow = screen->cur_row; 55 int width = MaxCols(screen); 56 unsigned len = (unsigned) width; 57 58 assert(width > 0); 59 60 /* 61 * Ignore repetition. 62 */ 63 if (!IsLeftRightMode(xw) 64 && (ld = getLineData(screen, currow)) != 0) { 65 unsigned oldChrSet = GetLineDblCS(ld); 66 67 if (oldChrSet != newChrSet) { 68 TRACE(("repaint_line(%2d,%2d) (%s -> %s)\n", currow, screen->cur_col, 69 visibleDblChrset(oldChrSet), 70 visibleDblChrset(newChrSet))); 71 HideCursor(); 72 73 /* If switching from single-width, keep the cursor in the visible part 74 * of the line. 75 */ 76 if (CSET_DOUBLE(newChrSet)) { 77 width /= 2; 78 if (curcol > width) 79 curcol = width; 80 } 81 82 /* 83 * ScrnRefresh won't paint blanks for us if we're switching between a 84 * single-size and double-size font. So we paint our own. 85 */ 86 ClearCurBackground(xw, 87 currow, 88 0, 89 1, 90 len, 91 (unsigned) LineFontWidth(screen, ld)); 92 93 SetLineDblCS(ld, newChrSet); 94 95 set_cur_col(screen, 0); 96 ScrnUpdate(xw, currow, 0, 1, (int) len, True); 97 set_cur_col(screen, curcol); 98 } 99 } 100} 101#endif 102 103/* 104 * Set the line to double-height characters. The 'top' flag denotes whether 105 * we'll be using it for the top (true) or bottom (false) of the line. 106 */ 107void 108xterm_DECDHL(XtermWidget xw GCC_UNUSED, Bool top) 109{ 110#if OPT_DEC_CHRSET 111 repaint_line(xw, (unsigned) (top ? CSET_DHL_TOP : CSET_DHL_BOT)); 112#else 113 (void) top; 114#endif 115} 116 117/* 118 * Set the line to single-width characters (the normal state). 119 */ 120void 121xterm_DECSWL(XtermWidget xw GCC_UNUSED) 122{ 123#if OPT_DEC_CHRSET 124 repaint_line(xw, CSET_SWL); 125#endif 126} 127 128/* 129 * Set the line to double-width characters 130 */ 131void 132xterm_DECDWL(XtermWidget xw GCC_UNUSED) 133{ 134#if OPT_DEC_CHRSET 135 repaint_line(xw, CSET_DWL); 136#endif 137} 138 139/* 140 * Reset all lines on the screen to single-width/single-height. 141 */ 142void 143xterm_ResetDouble(XtermWidget xw) 144{ 145#if OPT_DEC_CHRSET 146 TScreen *screen = TScreenOf(xw); 147 Boolean changed = False; 148 unsigned code; 149 int row; 150 151 for (row = 0; row < screen->max_row; ++row) { 152 LineData *ld; 153 154 if ((ld = getLineData(screen, ROW2INX(screen, row))) != 0) { 155 code = GetLineDblCS(ld); 156 if (code != CSET_SWL) { 157 SetLineDblCS(ld, CSET_SWL); 158 changed = True; 159 } 160 } 161 } 162 if (changed) { 163 xtermRepaint(xw); 164 } 165#else 166 (void) xw; 167#endif 168} 169 170#if OPT_DEC_CHRSET 171static void 172discard_font(XtermWidget xw, int n) 173{ 174 TScreen *screen = TScreenOf(xw); 175 XTermFonts *data = &(screen->double_fonts[n]); 176 177 TRACE(("discard_font chrset=%d %s\n", data->chrset, 178 (data->fn != 0) ? data->fn : "<no-name>")); 179 180 data->chrset = 0; 181 data->flags = 0; 182 if (data->fn != 0) { 183 free(data->fn); 184 data->fn = 0; 185 } 186 (void) xtermCloseFont(xw, data); 187 188 screen->fonts_used -= 1; 189 while (n < screen->fonts_used) { 190 screen->double_fonts[n] = screen->double_fonts[n + 1]; 191 ++n; 192 } 193} 194 195/* push back existing fonts and create a new entry */ 196static XTermFonts * 197pushback_font(XtermWidget xw, XTermFonts * source) 198{ 199 TScreen *screen = TScreenOf(xw); 200 XTermFonts *data = screen->double_fonts; 201 int n; 202 203 if (screen->fonts_used >= screen->cache_doublesize) { 204 TRACE(("pushback_font: discard oldest\n")); 205 discard_font(xw, screen->fonts_used - 1); 206 } else { 207 screen->fonts_used += 1; 208 } 209 210 for (n = screen->fonts_used; n > 0; n--) 211 data[n] = data[n - 1]; 212 data[0] = *source; 213 214 TRACE(("pushback_font -> (NEW:%d)\n", screen->fonts_used)); 215 216 return data; 217} 218 219int 220xterm_Double_index(XtermWidget xw, unsigned chrset, unsigned flags) 221{ 222 int n; 223 int result = -1; 224 TScreen *screen = TScreenOf(xw); 225 XTermFonts *data = screen->double_fonts; 226 227 flags &= BOLD; 228 TRACE(("xterm_Double_index chrset=%#x, flags=%#x\n", chrset, flags)); 229 230 for (n = 0; n < screen->fonts_used; n++) { 231 if (data[n].chrset == chrset 232 && data[n].flags == flags) { 233 if (n != 0) { 234 XTermFonts save; 235 TRACE(("...xterm_Double_index -> %d (OLD:%d)\n", n, screen->fonts_used)); 236 save = data[n]; 237 while (n > 0) { 238 data[n] = data[n - 1]; 239 n--; 240 } 241 data[n] = save; 242 } 243 result = n; 244 break; 245 } 246 } 247 248 return result; 249} 250 251/* 252 * Lookup/cache a GC for the double-size character display. We save up to 253 * NUM_CHRSET values. 254 */ 255GC 256xterm_DoubleGC(XtermWidget xw, 257 unsigned chrset, 258 unsigned attr_flags, 259 unsigned draw_flags, 260 GC old_gc, 261 int *inxp) 262{ 263 TScreen *screen = TScreenOf(xw); 264 VTwin *cgsWin = WhichVWin(screen); 265 char *name; 266 GC result = 0; 267 268 if ((name = xtermSpecialFont(screen, attr_flags, draw_flags, chrset)) != 0) { 269 CgsEnum cgsId = WhichCgsId(attr_flags); 270 Boolean found = False; 271 XTermFonts *data = 0; 272 int n; 273 274 if ((n = xterm_Double_index(xw, chrset, attr_flags)) >= 0) { 275 data = &(screen->double_fonts[n]); 276 if (data->fn != 0) { 277 if (!strcmp(data->fn, name) 278 && data->fs != 0) { 279 found = True; 280 free(name); 281 } else { 282 discard_font(xw, n); 283 } 284 } 285 } 286 287 if (!found) { 288 XTermFonts temp; 289 290 TRACE(("xterm_DoubleGC %s %d: %s\n", 291 (attr_flags & BOLD) ? "BOLD" : "NORM", n, name)); 292 293 memset(&temp, 0, sizeof(temp)); 294 temp.fn = name; 295 temp.chrset = chrset; 296 temp.flags = (attr_flags & BOLD); 297 298 if (!xtermOpenFont(xw, name, &temp, fwAlways, False)) { 299 /* Retry with * in resolutions */ 300 char *nname = xtermSpecialFont(screen, 301 attr_flags, 302 draw_flags | NORESOLUTION, 303 chrset); 304 305 if (nname != 0) { 306 found = (Boolean) xtermOpenFont(xw, nname, &temp, 307 fwAlways, False); 308 free(nname); 309 } 310 } else { 311 found = True; 312 } 313 free(name); 314 315 if (found) { 316 n = 0; 317 data = pushback_font(xw, &temp); 318 } 319 320 TRACE(("-> %s\n", found ? "OK" : "FAIL")); 321 } 322 323 if (found) { 324 setCgsCSet(xw, cgsWin, cgsId, chrset); 325 setCgsFont(xw, cgsWin, cgsId, data); 326 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, old_gc)); 327 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, old_gc)); 328 result = getCgsGC(xw, cgsWin, cgsId); 329 *inxp = n; 330 } else if (attr_flags & BOLD) { 331 UIntClr(attr_flags, BOLD); 332 result = xterm_DoubleGC(xw, chrset, 333 attr_flags, 334 draw_flags, 335 old_gc, inxp); 336 } 337 } 338 339 return result; 340} 341#endif 342