150276Speter/****************************************************************************
2174993Srafan * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996 on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter *	vidputs(newmode, outc)
3750276Speter *
3850276Speter *	newmode is taken to be the logical 'or' of the symbols in curses.h
3950276Speter *	representing graphic renditions.  The terminal is set to be in all of
4050276Speter *	the given modes, if possible.
4150276Speter *
4250276Speter *	if the new attribute is normal
4350276Speter *		if exit-alt-char-set exists
4450276Speter *			emit it
4550276Speter *		emit exit-attribute-mode
4650276Speter *	else if set-attributes exists
4750276Speter *		use it to set exactly what you want
4850276Speter *	else
4950276Speter *		if exit-attribute-mode exists
5050276Speter *			turn off everything
5150276Speter *		else
5250276Speter *			turn off those which can be turned off and aren't in
5350276Speter *			newmode.
5450276Speter *		turn on each mode which should be on and isn't, one by one
5550276Speter *
5650276Speter *	NOTE that this algorithm won't achieve the desired mix of attributes
5750276Speter *	in some cases, but those are probably just those cases in which it is
5850276Speter *	actually impossible, anyway, so...
5950276Speter *
6050276Speter * 	NOTE that we cannot assume that there's no interaction between color
6150276Speter *	and other attribute resets.  So each time we reset color (or other
6250276Speter *	attributes) we'll have to be prepared to restore the other.
6350276Speter */
6450276Speter
6550276Speter#include <curses.priv.h>
6650276Speter#include <term.h>
6750276Speter
68174993SrafanMODULE_ID("$Id: lib_vidattr.c,v 1.49 2007/06/30 21:58:04 tom Exp $")
6950276Speter
7050276Speter#define doPut(mode) TPUTS_TRACE(#mode); tputs(mode, 1, outc)
7150276Speter
7250276Speter#define TurnOn(mask,mode) \
7350276Speter	if ((turn_on & mask) && mode) { doPut(mode); }
7450276Speter
7550276Speter#define TurnOff(mask,mode) \
7650276Speter	if ((turn_off & mask) && mode) { doPut(mode); turn_off &= ~mask; }
7750276Speter
7850276Speter	/* if there is no current screen, assume we *can* do color */
7950276Speter#define SetColorsIf(why,old_attr) \
8062449Speter	if (can_color && (why)) { \
8150276Speter		int old_pair = PAIR_NUMBER(old_attr); \
8266963Speter		TR(TRACE_ATTRS, ("old pair = %d -- new pair = %d", old_pair, pair)); \
8350276Speter		if ((pair != old_pair) \
8462449Speter		 || (fix_pair0 && (pair == 0)) \
8550276Speter		 || (reverse ^ ((old_attr & A_REVERSE) != 0))) { \
8662449Speter			_nc_do_color(old_pair, pair, reverse, outc); \
8750276Speter		} \
8850276Speter	}
8950276Speter
90174993Srafan#define PreviousAttr _nc_prescreen.previous_attr
91174993Srafan
9276726SpeterNCURSES_EXPORT(int)
93166124Srafanvidputs(chtype newmode, int (*outc) (int))
9450276Speter{
9562449Speter    attr_t turn_on, turn_off;
9662449Speter    int pair;
9762449Speter    bool reverse = FALSE;
9862449Speter    bool can_color = (SP == 0 || SP->_coloron);
9966963Speter#if NCURSES_EXT_FUNCS
10062449Speter    bool fix_pair0 = (SP != 0 && SP->_coloron && !SP->_default_color);
10162449Speter#else
10262449Speter#define fix_pair0 FALSE
10362449Speter#endif
10450276Speter
105174993Srafan    newmode &= A_ATTRIBUTES;
10662449Speter    T((T_CALLED("vidputs(%s)"), _traceattr(newmode)));
10750276Speter
10862449Speter    /* this allows us to go on whether or not newterm() has been called */
10962449Speter    if (SP)
110174993Srafan	PreviousAttr = AttrOf(SCREEN_ATTRS(SP));
11150276Speter
112174993Srafan    TR(TRACE_ATTRS, ("previous attribute was %s", _traceattr(PreviousAttr)));
11350276Speter
11462449Speter    if ((SP != 0)
115166124Srafan	&& (magic_cookie_glitch > 0)) {
116166124Srafan#if USE_XMC_SUPPORT
117174993Srafan	static const chtype table[] =
118166124Srafan	{
119166124Srafan	    A_STANDOUT,
120166124Srafan	    A_UNDERLINE,
121166124Srafan	    A_REVERSE,
122166124Srafan	    A_BLINK,
123166124Srafan	    A_DIM,
124166124Srafan	    A_BOLD,
125166124Srafan	    A_INVIS,
126166124Srafan	    A_PROTECT,
127166124Srafan	};
128166124Srafan	unsigned n;
129166124Srafan	int used = 0;
130166124Srafan	int limit = (max_attributes <= 0) ? 1 : max_attributes;
131166124Srafan	chtype retain = 0;
132166124Srafan
133166124Srafan	/*
134166124Srafan	 * Limit the number of attribute bits set in the newmode according to
135166124Srafan	 * the terminfo max_attributes value.
136166124Srafan	 */
137166124Srafan	for (n = 0; n < SIZEOF(table); ++n) {
138166124Srafan	    if ((table[n] & SP->_ok_attributes) == 0) {
139166124Srafan		newmode &= ~table[n];
140166124Srafan	    } else if ((table[n] & newmode) != 0) {
141166124Srafan		if (used++ >= limit) {
142166124Srafan		    newmode &= ~table[n];
143166124Srafan		    if (newmode == retain)
144166124Srafan			break;
145166124Srafan		} else {
146166124Srafan		    retain = newmode;
147166124Srafan		}
148166124Srafan	    }
149166124Srafan	}
150166124Srafan#else
15162449Speter	newmode &= ~(SP->_xmc_suppress);
15250276Speter#endif
153166124Srafan	TR(TRACE_ATTRS, ("suppressed attribute is %s", _traceattr(newmode)));
154166124Srafan    }
15550276Speter
15662449Speter    /*
15762449Speter     * If we have a terminal that cannot combine color with video
15862449Speter     * attributes, use the colors in preference.
15962449Speter     */
16062449Speter    if (((newmode & A_COLOR) != 0
16166963Speter	 || fix_pair0)
16262449Speter	&& (no_color_video > 0)) {
16366963Speter	/*
16466963Speter	 * If we had chosen the A_xxx definitions to correspond to the
16566963Speter	 * no_color_video mask, we could simply shift it up and mask off the
16666963Speter	 * attributes.  But we did not (actually copied Solaris' definitions).
16766963Speter	 * However, this is still simpler/faster than a lookup table.
16866963Speter	 *
16966963Speter	 * The 63 corresponds to A_STANDOUT, A_UNDERLINE, A_REVERSE, A_BLINK,
17066963Speter	 * A_DIM, A_BOLD which are 1:1 with no_color_video.  The bits that
17166963Speter	 * correspond to A_INVIS, A_PROTECT (192) must be shifted up 1 and
17266963Speter	 * A_ALTCHARSET (256) down 2 to line up.  We use the NCURSES_BITS
17366963Speter	 * macro so this will work properly for the wide-character layout.
17466963Speter	 */
17576726Speter	unsigned value = no_color_video;
17676726Speter	attr_t mask = NCURSES_BITS((value & 63)
17776726Speter				   | ((value & 192) << 1)
17876726Speter				   | ((value & 256) >> 2), 8);
17962449Speter
18076726Speter	if ((mask & A_REVERSE) != 0
18176726Speter	    && (newmode & A_REVERSE) != 0) {
18266963Speter	    reverse = TRUE;
18366963Speter	    mask &= ~A_REVERSE;
18450276Speter	}
18566963Speter	newmode &= ~mask;
18662449Speter    }
18750276Speter
188174993Srafan    if (newmode == PreviousAttr)
18962449Speter	returnCode(OK);
19050276Speter
19162449Speter    pair = PAIR_NUMBER(newmode);
19250276Speter
19362449Speter    if (reverse) {
19462449Speter	newmode &= ~A_REVERSE;
19562449Speter    }
19650276Speter
197174993Srafan    turn_off = (~newmode & PreviousAttr) & ALL_BUT_COLOR;
198174993Srafan    turn_on = (newmode & ~PreviousAttr) & ALL_BUT_COLOR;
19950276Speter
200174993Srafan    SetColorsIf(((pair == 0) && !fix_pair0), PreviousAttr);
20150276Speter
20262449Speter    if (newmode == A_NORMAL) {
203174993Srafan	if ((PreviousAttr & A_ALTCHARSET) && exit_alt_charset_mode) {
20462449Speter	    doPut(exit_alt_charset_mode);
205174993Srafan	    PreviousAttr &= ~A_ALTCHARSET;
20662449Speter	}
207174993Srafan	if (PreviousAttr) {
20866963Speter	    if (exit_attribute_mode) {
20966963Speter		doPut(exit_attribute_mode);
21066963Speter	    } else {
21166963Speter		if (!SP || SP->_use_rmul) {
21266963Speter		    TurnOff(A_UNDERLINE, exit_underline_mode);
21366963Speter		}
21466963Speter		if (!SP || SP->_use_rmso) {
21566963Speter		    TurnOff(A_STANDOUT, exit_standout_mode);
21666963Speter		}
21766963Speter	    }
218174993Srafan	    PreviousAttr &= ALL_BUT_COLOR;
21962449Speter	}
22050276Speter
221174993Srafan	SetColorsIf((pair != 0) || fix_pair0, PreviousAttr);
22297049Speter    } else if (set_attributes) {
22362449Speter	if (turn_on || turn_off) {
22462449Speter	    TPUTS_TRACE("set_attributes");
22562449Speter	    tputs(tparm(set_attributes,
22666963Speter			(newmode & A_STANDOUT) != 0,
22766963Speter			(newmode & A_UNDERLINE) != 0,
22866963Speter			(newmode & A_REVERSE) != 0,
22966963Speter			(newmode & A_BLINK) != 0,
23066963Speter			(newmode & A_DIM) != 0,
23166963Speter			(newmode & A_BOLD) != 0,
23266963Speter			(newmode & A_INVIS) != 0,
23366963Speter			(newmode & A_PROTECT) != 0,
23466963Speter			(newmode & A_ALTCHARSET) != 0), 1, outc);
235174993Srafan	    PreviousAttr &= ALL_BUT_COLOR;
23662449Speter	}
237174993Srafan	SetColorsIf((pair != 0) || fix_pair0, PreviousAttr);
23862449Speter    } else {
23950276Speter
24066963Speter	TR(TRACE_ATTRS, ("turning %s off", _traceattr(turn_off)));
24150276Speter
24262449Speter	TurnOff(A_ALTCHARSET, exit_alt_charset_mode);
24350276Speter
24462449Speter	if (!SP || SP->_use_rmul) {
24562449Speter	    TurnOff(A_UNDERLINE, exit_underline_mode);
24662449Speter	}
24750276Speter
24862449Speter	if (!SP || SP->_use_rmso) {
24962449Speter	    TurnOff(A_STANDOUT, exit_standout_mode);
25062449Speter	}
25150276Speter
25262449Speter	if (turn_off && exit_attribute_mode) {
25362449Speter	    doPut(exit_attribute_mode);
254166124Srafan	    turn_on |= (newmode & ALL_BUT_COLOR);
255174993Srafan	    PreviousAttr &= ALL_BUT_COLOR;
25662449Speter	}
257174993Srafan	SetColorsIf((pair != 0) || fix_pair0, PreviousAttr);
25850276Speter
25966963Speter	TR(TRACE_ATTRS, ("turning %s on", _traceattr(turn_on)));
26062449Speter	/* *INDENT-OFF* */
26162449Speter	TurnOn(A_ALTCHARSET,	enter_alt_charset_mode);
26262449Speter	TurnOn(A_BLINK,		enter_blink_mode);
26362449Speter	TurnOn(A_BOLD,		enter_bold_mode);
26462449Speter	TurnOn(A_DIM,		enter_dim_mode);
26562449Speter	TurnOn(A_REVERSE,	enter_reverse_mode);
26662449Speter	TurnOn(A_STANDOUT,	enter_standout_mode);
26762449Speter	TurnOn(A_PROTECT,	enter_protected_mode);
26862449Speter	TurnOn(A_INVIS,		enter_secure_mode);
26962449Speter	TurnOn(A_UNDERLINE,	enter_underline_mode);
270166124Srafan#if USE_WIDEC_SUPPORT
27162449Speter	TurnOn(A_HORIZONTAL,	enter_horizontal_hl_mode);
27262449Speter	TurnOn(A_LEFT,		enter_left_hl_mode);
27362449Speter	TurnOn(A_LOW,		enter_low_hl_mode);
27462449Speter	TurnOn(A_RIGHT,		enter_right_hl_mode);
27562449Speter	TurnOn(A_TOP,		enter_top_hl_mode);
27662449Speter	TurnOn(A_VERTICAL,	enter_vertical_hl_mode);
27797049Speter#endif
27862449Speter	/* *INDENT-ON* */
27950276Speter
28062449Speter    }
28150276Speter
28262449Speter    if (reverse)
28362449Speter	newmode |= A_REVERSE;
28450276Speter
28562449Speter    if (SP)
286166124Srafan	SetAttr(SCREEN_ATTRS(SP), newmode);
28762449Speter    else
288174993Srafan	PreviousAttr = newmode;
28950276Speter
29062449Speter    returnCode(OK);
29150276Speter}
29250276Speter
29376726SpeterNCURSES_EXPORT(int)
29497049Spetervidattr(chtype newmode)
29550276Speter{
29662449Speter    T((T_CALLED("vidattr(%s)"), _traceattr(newmode)));
29750276Speter
29862449Speter    returnCode(vidputs(newmode, _nc_outch));
29950276Speter}
30050276Speter
30176726SpeterNCURSES_EXPORT(chtype)
30262449Spetertermattrs(void)
30350276Speter{
30462449Speter    chtype attrs = A_NORMAL;
30550276Speter
30666963Speter    T((T_CALLED("termattrs()")));
30762449Speter    if (enter_alt_charset_mode)
30862449Speter	attrs |= A_ALTCHARSET;
30950276Speter
31062449Speter    if (enter_blink_mode)
31162449Speter	attrs |= A_BLINK;
31250276Speter
31362449Speter    if (enter_bold_mode)
31462449Speter	attrs |= A_BOLD;
31550276Speter
31662449Speter    if (enter_dim_mode)
31762449Speter	attrs |= A_DIM;
31850276Speter
31962449Speter    if (enter_reverse_mode)
32062449Speter	attrs |= A_REVERSE;
32150276Speter
32262449Speter    if (enter_standout_mode)
32362449Speter	attrs |= A_STANDOUT;
32450276Speter
32562449Speter    if (enter_protected_mode)
32662449Speter	attrs |= A_PROTECT;
32750276Speter
32862449Speter    if (enter_secure_mode)
32962449Speter	attrs |= A_INVIS;
33050276Speter
33162449Speter    if (enter_underline_mode)
33262449Speter	attrs |= A_UNDERLINE;
33350276Speter
33462449Speter    if (SP->_coloron)
33562449Speter	attrs |= A_COLOR;
33650276Speter
33766963Speter    returnChar(attrs);
33850276Speter}
339