1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /*LINTLIBRARY*/ 43 44 #include <sys/types.h> 45 #include <stdlib.h> 46 #include "curses_inc.h" 47 48 #ifdef PC6300PLUS 49 #include <fcntl.h> 50 #include <sys/console.h> 51 #endif 52 53 #define NUM_OF_SPECIFIC_TURN_OFFS 3 54 extern chtype bit_attributes[]; 55 56 int Oldcolors[] = { COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, 57 COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE }; 58 59 void 60 vidupdate(chtype newmode, chtype oldmode, int (*outc)(char)) 61 { 62 bool color_terminal = (cur_term->_pairs_tbl) ? TRUE : FALSE; 63 chtype oldvideo = (oldmode & A_ATTRIBUTES) & ~A_COLOR; 64 chtype newvideo = (newmode & A_ATTRIBUTES) & ~A_COLOR; 65 int _change_video(chtype, chtype, int (*)(char)); 66 void _change_color(short, int (*)(char)); 67 68 /* if colors are used, extract the color related information from */ 69 /* the old and new modes and then erase color-pairs fields in */ 70 /* both arguments. */ 71 72 if (color_terminal) { 73 /* LINTED */ 74 short oldcolor = (short) PAIR_NUMBER(oldmode & A_COLOR); 75 /* LINTED */ 76 short newcolor = (short) PAIR_NUMBER(newmode & A_COLOR); 77 chtype turn_off = A_COLOR; 78 79 /* erase information about video attributes that could not */ 80 /* have been used with colors */ 81 82 if (oldcolor == 0) 83 oldvideo &= ~turn_off; 84 85 if (no_color_video != -1) 86 turn_off |= (((chtype) no_color_video) << 16); 87 88 if (oldcolor != 0) 89 oldvideo &= ~turn_off; 90 91 92 /* if the new mode contains color information, then first */ 93 /* deal with video attributes, and then with colors. This */ 94 /* way color information will overwrite video information. */ 95 96 if (newcolor != 0) { 97 /* erase information about video attributes that */ 98 /* should not be used with colors */ 99 100 newvideo &= ~turn_off; 101 102 /* if the new and the old video modes became */ 103 /* the same don't bother with them */ 104 105 if (newvideo != oldvideo) { 106 if ((_change_video(newvideo, oldvideo, 107 outc)) == -1) { 108 _Color_pair *cur_pair = 109 &cur_term->_cur_pair; 110 oldcolor = -1; 111 cur_pair->background = 112 cur_pair->foreground = -1; 113 } 114 } 115 if (newcolor != oldcolor) 116 _change_color(newcolor, outc); 117 } 118 119 /* new mode doesn't contain any color information. Deal */ 120 /* with colors first (possibly turning of the colors that */ 121 /* were contained in the oldmode, and then deal with video. */ 122 /* This way video attributes will overwrite colors. */ 123 124 else { 125 if (newcolor != oldcolor) 126 _change_color(newcolor, outc); 127 if (newvideo != oldvideo) 128 (void) _change_video(newvideo, oldvideo, outc); 129 } 130 } else 131 (void) _change_video(newvideo, oldvideo, outc); 132 } 133 134 135 int 136 _change_video(chtype newmode, chtype oldmode, int (*outc)(char)) 137 { 138 int rc = 0; 139 140 /* If you have set_attributes let the terminfo writer */ 141 /* worry about it. */ 142 143 if (!set_attributes) { 144 /* 145 * The trick is that we want to pre-process the new and oldmode 146 * so that we now know what they will really translate to on 147 * the physical screen. 148 * In the case where some attributes are being faked 149 * we get rid of the attributes being asked for and just have 150 * STANDOUT mode set. Therefore, if STANDOUT and UNDERLINE were 151 * on the screen but UNDERLINE was being faked to STANDOUT; and 152 * the new mode is just UNDERLINE, we will get rid of any faked 153 * modes and be left with and oldmode of STANDOUT and a new mode 154 * of STANDOUT, in which case the check for newmode and oldmode 155 * being equal will be true. 156 * 157 * 158 * This test is similar to the concept explained above. 159 * counter is the maximum attributes allowed on a terminal. 160 * For instance, on an hp/tvi950 without set_attributes 161 * the last video sequence sent will be the one the terminal 162 * will be in (on that spot). Therefore, in setupterm.c 163 * if ceol_standout_glitch or magic_cookie_glitch is set 164 * max_attributes is set to 1. This is because on those terminals 165 * only one attribute can be on at once. So, we pre-process the 166 * oldmode and the newmode and only leave the bits that are 167 * significant. In other words, if on an hp you ask for STANDOUT 168 * and UNDERLINE it will become only STANDOUT since that is the 169 * first bit that is looked at. If then the user goes from 170 * STANDOUT and UNDERLINE to STANDOUT and REVERSE the oldmode will 171 * become STANDOUT and the newmode will become STANDOUT. 172 * 173 * This also helps the code below in that on a hp or tvi950 only 174 * one bit will ever be set so that no code has to be added to 175 * cut out early in case two attributes were asked for. 176 */ 177 178 chtype check_faked, modes[2]; 179 int counter = max_attributes, i, j, tempmode; 180 int k = (cur_term->sgr_mode == oldmode) ? 1 : 2; 181 182 modes[0] = newmode; 183 modes[1] = oldmode; 184 185 while (k-- > 0) { 186 if ((check_faked = (modes[k] & 187 cur_term->sgr_faked)) != A_NORMAL) { 188 modes[k] &= ~check_faked; 189 modes[k] |= A_STANDOUT; 190 } 191 192 if ((j = counter) >= 0) { 193 tempmode = A_NORMAL; 194 if (j > 0) { 195 for (i = 0; i < NUM_ATTRIBUTES; i++) { 196 if (modes[k] & 197 bit_attributes[i]) { 198 tempmode |= 199 bit_attributes[i]; 200 if (--j == 0) 201 break; 202 } 203 } 204 } 205 modes[k] = tempmode; 206 } 207 } 208 newmode = modes[0]; 209 oldmode = modes[1]; 210 } 211 212 if (newmode == oldmode) 213 return (rc); 214 215 #ifdef DEBUG 216 if (outf) 217 fprintf(outf, "vidupdate oldmode=%o, newmode=%o\n", 218 oldmode, newmode); 219 #endif 220 221 if (set_attributes) { 222 (void) tputs(tparm(set_attributes, 223 newmode & A_STANDOUT, 224 newmode & A_UNDERLINE, 225 newmode & A_REVERSE, 226 newmode & A_BLINK, 227 newmode & A_DIM, 228 newmode & A_BOLD, 229 newmode & A_INVIS, 230 newmode & A_PROTECT, 231 newmode & A_ALTCHARSET), 232 1, outc); 233 rc = -1; 234 } else { 235 chtype turn_on, turn_off; 236 int i; 237 238 /* 239 * If we are going to turn something on anyway and we are 240 * on a glitchy terminal, don't bother turning it off 241 * since by turning something on you turn everything else off. 242 */ 243 244 if ((ceol_standout_glitch || magic_cookie_glitch >= 0) && 245 ((turn_on = ((oldmode ^ newmode) & newmode)) != 246 A_NORMAL)) { 247 goto turn_on_code; 248 } 249 250 if ((turn_off = (oldmode & newmode) ^ oldmode) != A_NORMAL) { 251 /* 252 * Check for things to turn off. 253 * First see if we are going to turn off something 254 * that doesn't have a specific turn off capability. 255 * 256 * Then check to see if, even though there may be a specific 257 * turn off sequence, this terminal doesn't have one or 258 * the turn off sequence also turns off something else. 259 */ 260 if ((turn_off & ~(A_ALTCHARSET | A_STANDOUT | A_UNDERLINE)) || 261 (turn_off != (turn_off & cur_term->check_turn_off))) { 262 (void) tputs(tparm_p0(exit_attribute_mode), 1, outc); 263 rc = -1; 264 oldmode = A_NORMAL; 265 } else { 266 for (i = 0; i < NUM_OF_SPECIFIC_TURN_OFFS; i++) { 267 if (turn_off & bit_attributes[i]) { 268 (void) tputs(tparm_p0 269 (cur_term->turn_off_seq[i]), 270 1, outc); 271 oldmode &= ~bit_attributes[i]; 272 rc = -1; 273 } 274 } 275 } 276 } 277 278 if ((turn_on = ((oldmode ^ newmode) & newmode)) != A_NORMAL) { 279 turn_on_code: 280 281 /* Check for modes to turn on. */ 282 283 for (i = 0; i < NUM_ATTRIBUTES; i++) 284 if (turn_on & bit_attributes[i]) { 285 (void) tputs(tparm_p0(cur_term->turn_on_seq[i]), 286 1, outc); 287 rc = -1; 288 /* 289 * Keep turning off the bit(s) that we just 290 * sent to the screen. As soon as turn_on 291 * reaches A_NORMAL we don't have to turn 292 * anything else on and we can 293 * break out of the loop. 294 */ 295 if ((turn_on &= ~bit_attributes[i]) == 296 A_NORMAL) 297 break; 298 } 299 } 300 301 if (magic_cookie_glitch > 0) 302 (void) tputs(cursor_left, 1, outc); 303 } 304 cur_term->sgr_mode = newmode; 305 return (rc); 306 } 307 308 309 void 310 _change_color(short newcolor, int (*outc)(char)) 311 { 312 #ifndef PC6300PLUS 313 { 314 _Color_pair *ptp = cur_term->_pairs_tbl; 315 /* pairs table pointer */ 316 _Color_pair *cur_pair = &cur_term->_cur_pair; 317 318 /* MORE: we may have to change some stuff, depending on whether */ 319 /* HP terminals will be changing the background, or not */ 320 321 if (newcolor == 0) { 322 if (orig_pair) 323 (void) tputs(tparm_p0(orig_pair), 1, outc); 324 if (set_a_background || set_a_foreground || 325 set_background || set_foreground) { 326 cur_pair->background = -1; 327 cur_pair->foreground = -1; 328 } 329 return; 330 } 331 332 /* if we are on HP type terminal, just send an escape sequence */ 333 /* to use desired color pair (we could have done some optimization: */ 334 /* check if both the foreground and background of newcolor match */ 335 /* the ones of cur_term->_cur_pair. but that will happen only when */ 336 /* two color pairs are defined exacly the same, and probably not */ 337 /* worth the effort). */ 338 339 if (set_color_pair) 340 (void) tputs(tparm_p1(set_color_pair, newcolor), 1, outc); 341 342 /* on Tek model we can do some optimization. */ 343 344 else { 345 if (ptp[newcolor].background != cur_pair->background) { 346 if (set_a_background) 347 (void) tputs(tparm_p1(set_a_background, 348 ptp[newcolor].background), 1, outc); 349 else if (set_background) 350 (void) tputs(tparm_p1(set_background, 351 Oldcolors[ptp[newcolor].background]), 352 1, outc); 353 cur_pair->background = ptp[newcolor].background; 354 } 355 if (ptp[newcolor].foreground != cur_pair->foreground) { 356 if (set_a_foreground) 357 (void) tputs(tparm_p1(set_a_foreground, 358 ptp[newcolor].foreground), 1, outc); 359 else if (set_foreground) 360 (void) tputs(tparm_p1(set_foreground, 361 Oldcolors[ptp[newcolor].foreground]), 362 1, outc); 363 cur_pair->foreground = ptp[newcolor].foreground; 364 } 365 } 366 } 367 #else 368 { 369 /* the following code is for PC6300 PLUS: it uses BOLD terminfo */ 370 /* entry for turning on colors, and SGR0 for turning them off. */ 371 /* Every time a new color-pair is used, we are forced to do an */ 372 /* ioctl read, and the send 'enter_bold_mode' escape sequence. */ 373 /* This could be improved by using */ 374 /* DIM, UNDERLINE, and REVERSE in addition to BOLD */ 375 376 struct console con; 377 _Color_pair *ptp = cur_term->_pairs_tbl; 378 /* pairs table pointer */ 379 back = ptp[newcolor].background; 380 fore = ptp[newcolor].foreground; 381 382 (void) fflush(SP->term_file); 383 ioctl(cur_term->Filedes, CONIOGETDATA, &con); 384 #define BOLD 4 385 con.l[con.page].colors[BOLD] = 386 ((back + back + (fore > 5)) * 8 + fore) & 0177; 387 ioctl(cur_term->Filedes, CONIOSETDATA, &con); 388 (void) tputs(enter_bold_mode, 1, outc); 389 } 390 #endif 391 } 392