doublechr.c revision e0a2b6df
1/* $XTermId: doublechr.c,v 1.83 2013/08/30 21:35:13 tom Exp $ */ 2 3/* 4 * Copyright 1997-2012,2013 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 LineData *ld; 149 unsigned code; 150 int row; 151 152 for (row = 0; row < screen->max_row; ++row) { 153 if ((ld = getLineData(screen, ROW2INX(screen, row))) != 0) { 154 code = GetLineDblCS(ld); 155 if (code != CSET_SWL) { 156 SetLineDblCS(ld, CSET_SWL); 157 changed = True; 158 } 159 } 160 } 161 if (changed) { 162 xtermRepaint(xw); 163 } 164#endif 165} 166 167#if OPT_DEC_CHRSET 168static void 169discard_font(XtermWidget xw, int n) 170{ 171 TScreen *screen = TScreenOf(xw); 172 XTermFonts *data = &(screen->double_fonts[n]); 173 174 TRACE(("discard_font chrset=%d %s\n", data->chrset, 175 (data->fn != 0) ? data->fn : "<no-name>")); 176 177 data->chrset = 0; 178 data->flags = 0; 179 if (data->fn != 0) { 180 free(data->fn); 181 data->fn = 0; 182 } 183 (void) xtermCloseFont(xw, data); 184 185 screen->fonts_used -= 1; 186 while (n < screen->fonts_used) { 187 screen->double_fonts[n] = screen->double_fonts[n + 1]; 188 ++n; 189 } 190} 191 192/* push back existing fonts and create a new entry */ 193static XTermFonts * 194pushback_font(XtermWidget xw, XTermFonts * source) 195{ 196 TScreen *screen = TScreenOf(xw); 197 XTermFonts *data = screen->double_fonts; 198 int n; 199 200 if (screen->fonts_used >= screen->cache_doublesize) { 201 TRACE(("pushback_font: discard oldest\n")); 202 discard_font(xw, screen->fonts_used - 1); 203 } else { 204 screen->fonts_used += 1; 205 } 206 207 for (n = screen->fonts_used; n > 0; n--) 208 data[n] = data[n - 1]; 209 data[0] = *source; 210 211 TRACE(("pushback_font -> (NEW:%d)\n", screen->fonts_used)); 212 213 return data; 214} 215 216int 217xterm_Double_index(XtermWidget xw, unsigned chrset, unsigned flags) 218{ 219 int n; 220 int result = -1; 221 TScreen *screen = TScreenOf(xw); 222 XTermFonts *data = screen->double_fonts; 223 224 flags &= BOLD; 225 TRACE(("xterm_Double_index chrset=%#x, flags=%#x\n", chrset, flags)); 226 227 for (n = 0; n < screen->fonts_used; n++) { 228 if (data[n].chrset == chrset 229 && data[n].flags == flags) { 230 if (n != 0) { 231 XTermFonts save; 232 TRACE(("...xterm_Double_index -> %d (OLD:%d)\n", n, screen->fonts_used)); 233 save = data[n]; 234 while (n > 0) { 235 data[n] = data[n - 1]; 236 n--; 237 } 238 data[n] = save; 239 } 240 result = n; 241 break; 242 } 243 } 244 245 return result; 246} 247 248/* 249 * Lookup/cache a GC for the double-size character display. We save up to 250 * NUM_CHRSET values. 251 */ 252GC 253xterm_DoubleGC(XtermWidget xw, 254 unsigned chrset, 255 unsigned flags, 256 GC old_gc, 257 int *inxp) 258{ 259 TScreen *screen = TScreenOf(xw); 260 VTwin *cgsWin = WhichVWin(screen); 261 int n; 262 char *name; 263 XTermFonts *data = 0; 264 GC result = 0; 265 266 if ((name = xtermSpecialFont(screen, flags, chrset)) != 0) { 267 CgsEnum cgsId = WhichCgsId(flags); 268 Boolean found = False; 269 270 if ((n = xterm_Double_index(xw, chrset, flags)) >= 0) { 271 data = &(screen->double_fonts[n]); 272 if (data->fn != 0) { 273 if (!strcmp(data->fn, name) 274 && data->fs != 0) { 275 found = True; 276 free(name); 277 } else { 278 discard_font(xw, n); 279 } 280 } 281 } 282 283 if (!found) { 284 XTermFonts temp; 285 286 TRACE(("xterm_DoubleGC %s %d: %s\n", 287 flags & BOLD ? "BOLD" : "NORM", n, name)); 288 289 memset(&temp, 0, sizeof(temp)); 290 temp.fn = name; 291 temp.chrset = chrset; 292 temp.flags = (flags & BOLD); 293 294 if (!xtermOpenFont(xw, name, &temp, fwAlways, False)) { 295 /* Retry with * in resolutions */ 296 char *nname = xtermSpecialFont(screen, flags | NORESOLUTION, chrset); 297 298 if (nname != 0) { 299 found = (Boolean) xtermOpenFont(xw, nname, &temp, 300 fwAlways, False); 301 free(nname); 302 } 303 } else { 304 found = True; 305 } 306 free(name); 307 308 if (found) { 309 n = 0; 310 data = pushback_font(xw, &temp); 311 } 312 313 TRACE(("-> %s\n", found ? "OK" : "FAIL")); 314 } 315 316 if (found) { 317 setCgsCSet(xw, cgsWin, cgsId, chrset); 318 setCgsFont(xw, cgsWin, cgsId, data); 319 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, old_gc)); 320 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, old_gc)); 321 result = getCgsGC(xw, cgsWin, cgsId); 322 *inxp = n; 323 } else if (flags & BOLD) { 324 UIntClr(flags, BOLD); 325 result = xterm_DoubleGC(xw, chrset, flags, old_gc, inxp); 326 } 327 } 328 329 return result; 330} 331#endif 332