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