Back to index

tetex-bin  3.0
lib_color.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
00031  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
00032  *     and: Thomas E. Dickey                        1996-on                 *
00033  ****************************************************************************/
00034 
00035 /* lib_color.c
00036  *
00037  * Handles color emulation of SYS V curses
00038  */
00039 
00040 #include <curses.priv.h>
00041 
00042 #include <term.h>
00043 #include <tic.h>
00044 
00045 MODULE_ID("$Id: lib_color.c,v 1.64 2004/09/25 22:49:16 tom Exp $")
00046 
00047 /*
00048  * These should be screen structure members.  They need to be globals for
00049  * historical reasons.  So we assign them in start_color() and also in
00050  * set_term()'s screen-switching logic.
00051  */
00052 NCURSES_EXPORT_VAR(int) COLOR_PAIRS = 0;
00053 NCURSES_EXPORT_VAR(int) COLORS = 0;
00054 
00055 #define DATA(r,g,b) {r,g,b, 0,0,0, 0}
00056 
00057 #define TYPE_CALLOC(type,elts) typeCalloc(type, (unsigned)(elts))
00058 
00059 /*
00060  * Given a RGB range of 0..1000, we'll normally set the individual values
00061  * to about 2/3 of the maximum, leaving full-range for bold/bright colors.
00062  */
00063 #define RGB_ON  680
00064 #define RGB_OFF 0
00065 /* *INDENT-OFF* */
00066 static const color_t cga_palette[] =
00067 {
00068     /*  R               G               B */
00069     DATA(RGB_OFF,    RGB_OFF,      RGB_OFF),     /* COLOR_BLACK */
00070     DATA(RGB_ON,     RGB_OFF,      RGB_OFF),     /* COLOR_RED */
00071     DATA(RGB_OFF,    RGB_ON,              RGB_OFF),     /* COLOR_GREEN */
00072     DATA(RGB_ON,     RGB_ON,              RGB_OFF),     /* COLOR_YELLOW */
00073     DATA(RGB_OFF,    RGB_OFF,      RGB_ON),      /* COLOR_BLUE */
00074     DATA(RGB_ON,     RGB_OFF,      RGB_ON),      /* COLOR_MAGENTA */
00075     DATA(RGB_OFF,    RGB_ON,              RGB_ON),      /* COLOR_CYAN */
00076     DATA(RGB_ON,     RGB_ON,              RGB_ON),      /* COLOR_WHITE */
00077 };
00078 
00079 static const color_t hls_palette[] =
00080 {
00081     /*        H       L       S */
00082     DATA(     0,     0,     0),           /* COLOR_BLACK */
00083     DATA(     120,   50,    100),         /* COLOR_RED */
00084     DATA(     240,   50,    100),         /* COLOR_GREEN */
00085     DATA(     180,   50,    100),         /* COLOR_YELLOW */
00086     DATA(     330,   50,    100),         /* COLOR_BLUE */
00087     DATA(     60,    50,    100),         /* COLOR_MAGENTA */
00088     DATA(     300,   50,    100),         /* COLOR_CYAN */
00089     DATA(     0,     50,    100),         /* COLOR_WHITE */
00090 };
00091 /* *INDENT-ON* */
00092 
00093 #if NCURSES_EXT_FUNCS
00094 /*
00095  * These are called from _nc_do_color(), which in turn is called from
00096  * vidattr - so we have to assume that SP may be null.
00097  */
00098 static int
00099 default_fg(void)
00100 {
00101     return (SP != 0) ? SP->_default_fg : COLOR_WHITE;
00102 }
00103 
00104 static int
00105 default_bg(void)
00106 {
00107     return SP != 0 ? SP->_default_bg : COLOR_BLACK;
00108 }
00109 #else
00110 #define default_fg() COLOR_WHITE
00111 #define default_bg() COLOR_BLACK
00112 #endif
00113 
00114 /*
00115  * SVr4 curses is known to interchange color codes (1,4) and (3,6), possibly
00116  * to maintain compatibility with a pre-ANSI scheme.  The same scheme is
00117  * also used in the FreeBSD syscons.
00118  */
00119 static int
00120 toggled_colors(int c)
00121 {
00122     if (c < 16) {
00123        static const int table[] =
00124        {0, 4, 2, 6, 1, 5, 3, 7,
00125         8, 12, 10, 14, 9, 13, 11, 15};
00126        c = table[c];
00127     }
00128     return c;
00129 }
00130 
00131 static void
00132 set_background_color(int bg, int (*outc) (int))
00133 {
00134     if (set_a_background) {
00135        TPUTS_TRACE("set_a_background");
00136        tputs(tparm(set_a_background, bg), 1, outc);
00137     } else {
00138        TPUTS_TRACE("set_background");
00139        tputs(tparm(set_background, toggled_colors(bg)), 1, outc);
00140     }
00141 }
00142 
00143 static void
00144 set_foreground_color(int fg, int (*outc) (int))
00145 {
00146     if (set_a_foreground) {
00147        TPUTS_TRACE("set_a_foreground");
00148        tputs(tparm(set_a_foreground, fg), 1, outc);
00149     } else {
00150        TPUTS_TRACE("set_foreground");
00151        tputs(tparm(set_foreground, toggled_colors(fg)), 1, outc);
00152     }
00153 }
00154 
00155 static void
00156 init_color_table(void)
00157 {
00158     const color_t *tp;
00159     int n;
00160 
00161     tp = (hue_lightness_saturation) ? hls_palette : cga_palette;
00162     for (n = 0; n < COLORS; n++) {
00163        if (n < 8) {
00164            SP->_color_table[n] = tp[n];
00165        } else {
00166            SP->_color_table[n] = tp[n % 8];
00167            if (hue_lightness_saturation) {
00168               SP->_color_table[n].green = 100;
00169            } else {
00170               if (SP->_color_table[n].red)
00171                   SP->_color_table[n].red = 1000;
00172               if (SP->_color_table[n].green)
00173                   SP->_color_table[n].green = 1000;
00174               if (SP->_color_table[n].blue)
00175                   SP->_color_table[n].blue = 1000;
00176            }
00177        }
00178     }
00179 }
00180 
00181 /*
00182  * Reset the color pair, e.g., to whatever color pair 0 is.
00183  */
00184 static bool
00185 reset_color_pair(void)
00186 {
00187     bool result = FALSE;
00188 
00189     if (orig_pair != 0) {
00190        TPUTS_TRACE("orig_pair");
00191        putp(orig_pair);
00192        result = TRUE;
00193     }
00194     return result;
00195 }
00196 
00197 /*
00198  * Reset color pairs and definitions.  Actually we do both more to accommodate
00199  * badly-written terminal descriptions than for the relatively rare case where
00200  * someone has changed the color definitions.
00201  */
00202 bool
00203 _nc_reset_colors(void)
00204 {
00205     int result = FALSE;
00206 
00207     T((T_CALLED("_nc_reset_colors()")));
00208     if (SP->_color_defs > 0)
00209        SP->_color_defs = -(SP->_color_defs);
00210 
00211     if (reset_color_pair())
00212        result = TRUE;
00213     if (orig_colors != 0) {
00214        TPUTS_TRACE("orig_colors");
00215        putp(orig_colors);
00216        result = TRUE;
00217     }
00218     returnBool(result);
00219 }
00220 
00221 NCURSES_EXPORT(int)
00222 start_color(void)
00223 {
00224     int result = ERR;
00225 
00226     T((T_CALLED("start_color()")));
00227 
00228     if (!SP->_coloron) {
00229 
00230        if (reset_color_pair() != TRUE) {
00231            set_foreground_color(default_fg(), _nc_outch);
00232            set_background_color(default_bg(), _nc_outch);
00233        }
00234 
00235        if (max_pairs > 0 && max_colors > 0) {
00236            COLOR_PAIRS = SP->_pair_count = max_pairs;
00237            COLORS = SP->_color_count = max_colors;
00238 
00239            if ((SP->_color_pairs = TYPE_CALLOC(unsigned short,
00240                                           max_pairs)) != 0) {
00241               if ((SP->_color_table = TYPE_CALLOC(color_t,
00242                                               max_colors)) != 0) {
00243                   SP->_color_pairs[0] = PAIR_OF(default_fg(), default_bg());
00244                   init_color_table();
00245 
00246                   T(("started color: COLORS = %d, COLOR_PAIRS = %d",
00247                      COLORS, COLOR_PAIRS));
00248 
00249                   SP->_coloron = 1;
00250                   result = OK;
00251               } else {
00252                   FreeAndNull(SP->_color_pairs);
00253               }
00254            }
00255        }
00256     }
00257     returnCode(OK);
00258 }
00259 
00260 /* This function was originally written by Daniel Weaver <danw@znyx.com> */
00261 static void
00262 rgb2hls(short r, short g, short b, short *h, short *l, short *s)
00263 /* convert RGB to HLS system */
00264 {
00265     short min, max, t;
00266 
00267     if ((min = g < r ? g : r) > b)
00268        min = b;
00269     if ((max = g > r ? g : r) < b)
00270        max = b;
00271 
00272     /* calculate lightness */
00273     *l = (min + max) / 20;
00274 
00275     if (min == max) {              /* black, white and all shades of gray */
00276        *h = 0;
00277        *s = 0;
00278        return;
00279     }
00280 
00281     /* calculate saturation */
00282     if (*l < 50)
00283        *s = ((max - min) * 100) / (max + min);
00284     else
00285        *s = ((max - min) * 100) / (2000 - max - min);
00286 
00287     /* calculate hue */
00288     if (r == max)
00289        t = 120 + ((g - b) * 60) / (max - min);
00290     else if (g == max)
00291        t = 240 + ((b - r) * 60) / (max - min);
00292     else
00293        t = 360 + ((r - g) * 60) / (max - min);
00294 
00295     *h = t % 360;
00296 }
00297 
00298 /*
00299  * Extension (1997/1/18) - Allow negative f/b values to set default color
00300  * values.
00301  */
00302 NCURSES_EXPORT(int)
00303 init_pair(short pair, short f, short b)
00304 {
00305     unsigned result;
00306 
00307     T((T_CALLED("init_pair(%d,%d,%d)"), pair, f, b));
00308 
00309     if ((pair < 0) || (pair >= COLOR_PAIRS))
00310        returnCode(ERR);
00311 #if NCURSES_EXT_FUNCS
00312     if (SP->_default_color) {
00313        if (f < 0)
00314            f = C_MASK;
00315        if (b < 0)
00316            b = C_MASK;
00317        if (f >= COLORS && f != C_MASK)
00318            returnCode(ERR);
00319        if (b >= COLORS && b != C_MASK)
00320            returnCode(ERR);
00321     } else
00322 #endif
00323     {
00324        if ((f < 0) || (f >= COLORS)
00325            || (b < 0) || (b >= COLORS)
00326            || (pair < 1))
00327            returnCode(ERR);
00328     }
00329 
00330     /*
00331      * When a pair's content is changed, replace its colors (if pair was
00332      * initialized before a screen update is performed replacing original
00333      * pair colors with the new ones).
00334      */
00335     result = PAIR_OF(f, b);
00336     if (SP->_color_pairs[pair] != 0
00337        && SP->_color_pairs[pair] != result) {
00338        int y, x;
00339        attr_t z = COLOR_PAIR(pair);
00340 
00341        for (y = 0; y <= curscr->_maxy; y++) {
00342            struct ldat *ptr = &(curscr->_line[y]);
00343            bool changed = FALSE;
00344            for (x = 0; x <= curscr->_maxx; x++) {
00345               if ((AttrOf(ptr->text[x]) & A_COLOR) == z) {
00346                   /* Set the old cell to zero to ensure it will be
00347                      updated on the next doupdate() */
00348                   SetChar(ptr->text[x], 0, 0);
00349                   CHANGED_CELL(ptr, x);
00350                   changed = TRUE;
00351               }
00352            }
00353            if (changed)
00354               _nc_make_oldhash(y);
00355        }
00356     }
00357     SP->_color_pairs[pair] = result;
00358     if ((int) (SP->_current_attr & A_COLOR) == COLOR_PAIR(pair))
00359        SP->_current_attr |= A_COLOR;      /* force attribute update */
00360 
00361     if (initialize_pair) {
00362        const color_t *tp = hue_lightness_saturation ? hls_palette : cga_palette;
00363 
00364        T(("initializing pair: pair = %d, fg=(%d,%d,%d), bg=(%d,%d,%d)",
00365           pair,
00366           tp[f].red, tp[f].green, tp[f].blue,
00367           tp[b].red, tp[b].green, tp[b].blue));
00368 
00369        if (initialize_pair) {
00370            TPUTS_TRACE("initialize_pair");
00371            putp(tparm(initialize_pair,
00372                      pair,
00373                      tp[f].red, tp[f].green, tp[f].blue,
00374                      tp[b].red, tp[b].green, tp[b].blue));
00375        }
00376     }
00377 
00378     returnCode(OK);
00379 }
00380 
00381 #define okRGB(n) ((n) >= 0 && (n) <= 1000)
00382 
00383 NCURSES_EXPORT(int)
00384 init_color(short color, short r, short g, short b)
00385 {
00386     int result = ERR;
00387 
00388     T((T_CALLED("init_color(%d,%d,%d,%d)"), color, r, g, b));
00389 
00390     if (initialize_color != NULL
00391        && (color >= 0 && color < COLORS)
00392        && (okRGB(r) && okRGB(g) && okRGB(b))) {
00393 
00394        SP->_color_table[color].init = 1;
00395        SP->_color_table[color].r = r;
00396        SP->_color_table[color].g = g;
00397        SP->_color_table[color].b = b;
00398 
00399        if (hue_lightness_saturation) {
00400            rgb2hls(r, g, b,
00401                   &SP->_color_table[color].red,
00402                   &SP->_color_table[color].green,
00403                   &SP->_color_table[color].blue);
00404        } else {
00405            SP->_color_table[color].red = r;
00406            SP->_color_table[color].green = g;
00407            SP->_color_table[color].blue = b;
00408        }
00409 
00410        TPUTS_TRACE("initialize_color");
00411        putp(tparm(initialize_color, color, r, g, b));
00412        SP->_color_defs = max(color + 1, SP->_color_defs);
00413        result = OK;
00414     }
00415     returnCode(result);
00416 }
00417 
00418 NCURSES_EXPORT(bool)
00419 can_change_color(void)
00420 {
00421     T((T_CALLED("can_change_color()")));
00422     returnCode((can_change != 0) ? TRUE : FALSE);
00423 }
00424 
00425 NCURSES_EXPORT(bool)
00426 has_colors(void)
00427 {
00428     T((T_CALLED("has_colors()")));
00429     returnCode((VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
00430               && (((set_foreground != NULL)
00431                    && (set_background != NULL))
00432                   || ((set_a_foreground != NULL)
00433                      && (set_a_background != NULL))
00434                   || set_color_pair)) ? TRUE : FALSE);
00435 }
00436 
00437 NCURSES_EXPORT(int)
00438 color_content(short color, short *r, short *g, short *b)
00439 {
00440     T((T_CALLED("color_content(%d,%p,%p,%p)"), color, r, g, b));
00441     if (color < 0 || color >= COLORS)
00442        returnCode(ERR);
00443 
00444     if (r)
00445        *r = SP->_color_table[color].red;
00446     if (g)
00447        *g = SP->_color_table[color].green;
00448     if (b)
00449        *b = SP->_color_table[color].blue;
00450     T(("...color_content(%d,%d,%d,%d)", color, *r, *g, *b));
00451     returnCode(OK);
00452 }
00453 
00454 NCURSES_EXPORT(int)
00455 pair_content(short pair, short *f, short *b)
00456 {
00457     T((T_CALLED("pair_content(%d,%p,%p)"), pair, f, b));
00458 
00459     if ((pair < 0) || (pair >= COLOR_PAIRS))
00460        returnCode(ERR);
00461     if (f)
00462        *f = ((SP->_color_pairs[pair] >> C_SHIFT) & C_MASK);
00463     if (b)
00464        *b = (SP->_color_pairs[pair] & C_MASK);
00465 
00466     T(("...pair_content(%d,%d,%d)", pair, *f, *b));
00467     returnCode(OK);
00468 }
00469 
00470 NCURSES_EXPORT(void)
00471 _nc_do_color(int old_pair, int pair, bool reverse, int (*outc) (int))
00472 {
00473     NCURSES_COLOR_T fg = C_MASK, bg = C_MASK;
00474     NCURSES_COLOR_T old_fg, old_bg;
00475 
00476     if (pair < 0 || pair >= COLOR_PAIRS) {
00477        return;
00478     } else if (pair != 0) {
00479        if (set_color_pair) {
00480            TPUTS_TRACE("set_color_pair");
00481            tputs(tparm(set_color_pair, pair), 1, outc);
00482            return;
00483        } else if (SP != 0) {
00484            pair_content(pair, &fg, &bg);
00485        }
00486     }
00487 
00488     if (old_pair >= 0
00489        && SP != 0
00490        && pair_content(old_pair, &old_fg, &old_bg) != ERR) {
00491        if ((fg == C_MASK && old_fg != C_MASK)
00492            || (bg == C_MASK && old_bg != C_MASK)) {
00493 #if NCURSES_EXT_FUNCS
00494            /*
00495             * A minor optimization - but extension.  If "AX" is specified in
00496             * the terminal description, treat it as screen's indicator of ECMA
00497             * SGR 39 and SGR 49, and assume the two sequences are independent.
00498             */
00499            if (SP->_has_sgr_39_49 && old_bg == C_MASK && old_fg != C_MASK) {
00500               tputs("\033[39m", 1, outc);
00501            } else if (SP->_has_sgr_39_49 && old_fg == C_MASK && old_bg != C_MASK) {
00502               tputs("\033[49m", 1, outc);
00503            } else
00504 #endif
00505               reset_color_pair();
00506        }
00507     } else {
00508        reset_color_pair();
00509        if (old_pair < 0)
00510            return;
00511     }
00512 
00513 #if NCURSES_EXT_FUNCS
00514     if (fg == C_MASK)
00515        fg = default_fg();
00516     if (bg == C_MASK)
00517        bg = default_bg();
00518 #endif
00519 
00520     if (reverse) {
00521        NCURSES_COLOR_T xx = fg;
00522        fg = bg;
00523        bg = xx;
00524     }
00525 
00526     TR(TRACE_ATTRS, ("setting colors: pair = %d, fg = %d, bg = %d", pair,
00527                    fg, bg));
00528 
00529     if (fg != C_MASK) {
00530        set_foreground_color(fg, outc);
00531     }
00532     if (bg != C_MASK) {
00533        set_background_color(bg, outc);
00534     }
00535 }