1 /* $OpenBSD: lib_set_term.c,v 1.13 2010/01/12 23:22:06 nicm Exp $ */ 2 3 /**************************************************************************** 4 * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 5 * * 6 * Permission is hereby granted, free of charge, to any person obtaining a * 7 * copy of this software and associated documentation files (the * 8 * "Software"), to deal in the Software without restriction, including * 9 * without limitation the rights to use, copy, modify, merge, publish, * 10 * distribute, distribute with modifications, sublicense, and/or sell * 11 * copies of the Software, and to permit persons to whom the Software is * 12 * furnished to do so, subject to the following conditions: * 13 * * 14 * The above copyright notice and this permission notice shall be included * 15 * in all copies or substantial portions of the Software. * 16 * * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 20 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 23 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 24 * * 25 * Except as contained in this notice, the name(s) of the above copyright * 26 * holders shall not be used in advertising or otherwise to promote the * 27 * sale, use or other dealings in this Software without prior written * 28 * authorization. * 29 ****************************************************************************/ 30 31 /**************************************************************************** 32 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 33 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 34 * and: Thomas E. Dickey 1996-on * 35 ****************************************************************************/ 36 37 /* 38 ** lib_set_term.c 39 ** 40 ** The routine set_term(). 41 ** 42 */ 43 44 #include <curses.priv.h> 45 46 #include <term.h> /* cur_term */ 47 #include <tic.h> 48 49 MODULE_ID("$Id: lib_set_term.c,v 1.13 2010/01/12 23:22:06 nicm Exp $") 50 51 NCURSES_EXPORT(SCREEN *) 52 set_term(SCREEN *screenp) 53 { 54 SCREEN *oldSP; 55 SCREEN *newSP; 56 57 T((T_CALLED("set_term(%p)"), screenp)); 58 59 _nc_lock_global(curses); 60 61 oldSP = SP; 62 _nc_set_screen(screenp); 63 newSP = SP; 64 65 if (newSP != 0) { 66 set_curterm(newSP->_term); 67 #if !USE_REENTRANT 68 curscr = newSP->_curscr; 69 newscr = newSP->_newscr; 70 stdscr = newSP->_stdscr; 71 COLORS = newSP->_color_count; 72 COLOR_PAIRS = newSP->_pair_count; 73 #endif 74 } else { 75 set_curterm(0); 76 #if !USE_REENTRANT 77 curscr = 0; 78 newscr = 0; 79 stdscr = 0; 80 COLORS = 0; 81 COLOR_PAIRS = 0; 82 #endif 83 } 84 85 _nc_unlock_global(curses); 86 87 T((T_RETURN("%p"), oldSP)); 88 return (oldSP); 89 } 90 91 static void 92 _nc_free_keytry(TRIES * kt) 93 { 94 if (kt != 0) { 95 _nc_free_keytry(kt->child); 96 _nc_free_keytry(kt->sibling); 97 free(kt); 98 } 99 } 100 101 static bool 102 delink_screen(SCREEN *sp) 103 { 104 SCREEN *last = 0; 105 SCREEN *temp; 106 bool result = FALSE; 107 108 for (each_screen(temp)) { 109 if (temp == sp) { 110 if (last) 111 last = sp->_next_screen; 112 else 113 _nc_screen_chain = sp->_next_screen; 114 result = TRUE; 115 break; 116 } 117 last = temp; 118 } 119 return result; 120 } 121 122 /* 123 * Free the storage associated with the given SCREEN sp. 124 */ 125 NCURSES_EXPORT(void) 126 delscreen(SCREEN *sp) 127 { 128 int i; 129 130 T((T_CALLED("delscreen(%p)"), sp)); 131 132 _nc_lock_global(curses); 133 if (delink_screen(sp)) { 134 135 (void) _nc_freewin(sp->_curscr); 136 (void) _nc_freewin(sp->_newscr); 137 (void) _nc_freewin(sp->_stdscr); 138 139 if (sp->_slk != 0) { 140 if (sp->_slk->ent != 0) { 141 for (i = 0; i < sp->_slk->labcnt; ++i) { 142 FreeIfNeeded(sp->_slk->ent[i].ent_text); 143 FreeIfNeeded(sp->_slk->ent[i].form_text); 144 } 145 free(sp->_slk->ent); 146 } 147 free(sp->_slk); 148 sp->_slk = 0; 149 } 150 151 _nc_free_keytry(sp->_keytry); 152 sp->_keytry = 0; 153 154 _nc_free_keytry(sp->_key_ok); 155 sp->_key_ok = 0; 156 157 FreeIfNeeded(sp->_current_attr); 158 159 FreeIfNeeded(sp->_color_table); 160 FreeIfNeeded(sp->_color_pairs); 161 162 FreeIfNeeded(sp->oldhash); 163 FreeIfNeeded(sp->newhash); 164 FreeIfNeeded(sp->hashtab); 165 166 FreeIfNeeded(sp->_acs_map); 167 FreeIfNeeded(sp->_screen_acs_map); 168 169 /* 170 * If the associated output stream has been closed, we can discard the 171 * set-buffer. Limit the error check to EBADF, since fflush may fail 172 * for other reasons than trying to operate upon a closed stream. 173 */ 174 if (sp->_ofp != 0 175 && sp->_setbuf != 0 176 && fflush(sp->_ofp) != 0 177 && errno == EBADF) { 178 free(sp->_setbuf); 179 } 180 181 del_curterm(sp->_term); 182 free(sp); 183 184 /* 185 * If this was the current screen, reset everything that the 186 * application might try to use (except cur_term, which may have 187 * multiple references in different screens). 188 */ 189 if (sp == SP) { 190 #if !USE_REENTRANT 191 curscr = 0; 192 newscr = 0; 193 stdscr = 0; 194 COLORS = 0; 195 COLOR_PAIRS = 0; 196 #endif 197 _nc_set_screen(0); 198 } 199 } 200 _nc_unlock_global(curses); 201 202 returnVoid; 203 } 204 205 static bool 206 no_mouse_event(SCREEN *sp GCC_UNUSED) 207 { 208 return FALSE; 209 } 210 211 static bool 212 no_mouse_inline(SCREEN *sp GCC_UNUSED) 213 { 214 return FALSE; 215 } 216 217 static bool 218 no_mouse_parse(SCREEN *sp GCC_UNUSED, int code GCC_UNUSED) 219 { 220 return TRUE; 221 } 222 223 static void 224 no_mouse_resume(SCREEN *sp GCC_UNUSED) 225 { 226 } 227 228 static void 229 no_mouse_wrap(SCREEN *sp GCC_UNUSED) 230 { 231 } 232 233 #if NCURSES_EXT_FUNCS && USE_COLORFGBG 234 static char * 235 extract_fgbg(char *src, int *result) 236 { 237 char *dst = 0; 238 long value = strtol(src, &dst, 0); 239 240 if (dst == 0) { 241 dst = src; 242 } else if (value >= 0) { 243 *result = value; 244 } 245 while (*dst != 0 && *dst != ';') 246 dst++; 247 if (*dst == ';') 248 dst++; 249 return dst; 250 } 251 #endif 252 253 /* OS-independent screen initializations */ 254 NCURSES_EXPORT(int) 255 _nc_setupscreen(int slines GCC_UNUSED, 256 int scolumns GCC_UNUSED, 257 FILE *output, 258 bool filtered, 259 int slk_format) 260 { 261 char *env; 262 int bottom_stolen = 0; 263 bool support_cookies = USE_XMC_SUPPORT; 264 ripoff_t *rop; 265 266 T((T_CALLED("_nc_setupscreen(%d, %d, %p, %d, %d)"), 267 slines, scolumns, output, filtered, slk_format)); 268 269 assert(SP == 0); /* has been reset in newterm() ! */ 270 if (!_nc_alloc_screen() 271 || ((SP->_acs_map = typeCalloc(chtype, ACS_LEN)) == 0) 272 || ((SP->_screen_acs_map = typeCalloc(bool, ACS_LEN)) == 0)) { 273 returnCode(ERR); 274 } 275 276 T(("created SP %p", SP)); 277 SP->_next_screen = _nc_screen_chain; 278 _nc_screen_chain = SP; 279 280 if ((SP->_current_attr = typeCalloc(NCURSES_CH_T, 1)) == 0) 281 returnCode(ERR); 282 283 /* 284 * We should always check the screensize, just in case. 285 */ 286 _nc_get_screensize(SP, &slines, &scolumns); 287 SET_LINES(slines); 288 SET_COLS(scolumns); 289 T((T_CREATE("screen %s %dx%d"), termname(), LINES, COLS)); 290 291 SP->_filtered = filtered; 292 293 /* implement filter mode */ 294 if (filtered) { 295 slines = 1; 296 SET_LINES(slines); 297 clear_screen = 0; 298 cursor_down = parm_down_cursor = 0; 299 cursor_address = 0; 300 cursor_up = parm_up_cursor = 0; 301 row_address = 0; 302 303 cursor_home = carriage_return; 304 T(("filter screensize %dx%d", LINES, COLS)); 305 } 306 #ifdef __DJGPP__ 307 T(("setting output mode to binary")); 308 fflush(output); 309 setmode(output, O_BINARY); 310 #endif 311 _nc_set_buffer(output, TRUE); 312 SP->_term = cur_term; 313 SP->_lines = slines; 314 SP->_lines_avail = slines; 315 SP->_columns = scolumns; 316 SP->_cursrow = -1; 317 SP->_curscol = -1; 318 SP->_nl = TRUE; 319 SP->_raw = FALSE; 320 SP->_cbreak = 0; 321 SP->_echo = TRUE; 322 SP->_fifohead = -1; 323 SP->_endwin = TRUE; 324 SP->_ofp = output; 325 SP->_cursor = -1; /* cannot know real cursor shape */ 326 327 SetNoPadding(SP); 328 329 #if NCURSES_EXT_FUNCS 330 SP->_default_color = FALSE; 331 SP->_has_sgr_39_49 = FALSE; 332 333 /* 334 * Set our assumption of the terminal's default foreground and background 335 * colors. The curs_color man-page states that we can assume that the 336 * background is black. The origin of this assumption appears to be 337 * terminals that displayed colored text, but no colored backgrounds, e.g., 338 * the first colored terminals around 1980. More recent ones with better 339 * technology can display not only colored backgrounds, but all 340 * combinations. So a terminal might be something other than "white" on 341 * black (green/black looks monochrome too), but black on white or even 342 * on ivory. 343 * 344 * White-on-black is the simplest thing to use for monochrome. Almost 345 * all applications that use color paint both text and background, so 346 * the distinction is moot. But a few do not - which is why we leave this 347 * configurable (a better solution is to use assume_default_colors() for 348 * the rare applications that do require that sort of appearance, since 349 * is appears that more users expect to be able to make a white-on-black 350 * or black-on-white display under control of the application than not). 351 */ 352 #ifdef USE_ASSUMED_COLOR 353 SP->_default_fg = COLOR_WHITE; 354 SP->_default_bg = COLOR_BLACK; 355 #else 356 SP->_default_fg = C_MASK; 357 SP->_default_bg = C_MASK; 358 #endif 359 360 /* 361 * Allow those assumed/default color assumptions to be overridden at 362 * runtime: 363 */ 364 if ((env = getenv("NCURSES_ASSUMED_COLORS")) != 0) { 365 int fg, bg; 366 char sep1, sep2; 367 int count = sscanf(env, "%d%c%d%c", &fg, &sep1, &bg, &sep2); 368 if (count >= 1) { 369 SP->_default_fg = (fg >= 0 && fg < max_colors) ? fg : C_MASK; 370 if (count >= 3) { 371 SP->_default_bg = (bg >= 0 && bg < max_colors) ? bg : C_MASK; 372 } 373 TR(TRACE_CHARPUT | TRACE_MOVE, 374 ("from environment assumed fg=%d, bg=%d", 375 SP->_default_fg, 376 SP->_default_bg)); 377 } 378 } 379 #if USE_COLORFGBG 380 /* 381 * If rxvt's $COLORFGBG variable is set, use it to specify the assumed 382 * default colors. Note that rxvt (mis)uses bold colors, equating a bold 383 * color to that value plus 8. We'll only use the non-bold color for now - 384 * decide later if it is worth having default attributes as well. 385 */ 386 if (getenv("COLORFGBG") != 0) { 387 char *p = getenv("COLORFGBG"); 388 TR(TRACE_CHARPUT | TRACE_MOVE, ("decoding COLORFGBG %s", p)); 389 p = extract_fgbg(p, &(SP->_default_fg)); 390 p = extract_fgbg(p, &(SP->_default_bg)); 391 if (*p) /* assume rxvt was compiled with xpm support */ 392 p = extract_fgbg(p, &(SP->_default_bg)); 393 TR(TRACE_CHARPUT | TRACE_MOVE, ("decoded fg=%d, bg=%d", 394 SP->_default_fg, SP->_default_bg)); 395 if (SP->_default_fg >= max_colors) { 396 if (set_a_foreground != ABSENT_STRING 397 && !strcmp(set_a_foreground, "\033[3%p1%dm")) { 398 set_a_foreground = "\033[3%?%p1%{8}%>%t9%e%p1%d%;m"; 399 } else { 400 SP->_default_fg %= max_colors; 401 } 402 } 403 if (SP->_default_bg >= max_colors) { 404 if (set_a_background != ABSENT_STRING 405 && !strcmp(set_a_background, "\033[4%p1%dm")) { 406 set_a_background = "\033[4%?%p1%{8}%>%t9%e%p1%d%;m"; 407 } else { 408 SP->_default_bg %= max_colors; 409 } 410 } 411 } 412 #endif 413 #endif /* NCURSES_EXT_FUNCS */ 414 415 SP->_maxclick = DEFAULT_MAXCLICK; 416 SP->_mouse_event = no_mouse_event; 417 SP->_mouse_inline = no_mouse_inline; 418 SP->_mouse_parse = no_mouse_parse; 419 SP->_mouse_resume = no_mouse_resume; 420 SP->_mouse_wrap = no_mouse_wrap; 421 SP->_mouse_fd = -1; 422 423 /* 424 * If we've no magic cookie support, we suppress attributes that xmc would 425 * affect, i.e., the attributes that affect the rendition of a space. 426 */ 427 SP->_ok_attributes = termattrs(); 428 if (has_colors()) { 429 SP->_ok_attributes |= A_COLOR; 430 } 431 #if USE_XMC_SUPPORT 432 /* 433 * If we have no magic-cookie support compiled-in, or if it is suppressed 434 * in the environment, reset the support-flag. 435 */ 436 if (magic_cookie_glitch >= 0) { 437 if (getenv("NCURSES_NO_MAGIC_COOKIE") != 0) { 438 support_cookies = FALSE; 439 } 440 } 441 #endif 442 443 if (!support_cookies && magic_cookie_glitch >= 0) { 444 T(("will disable attributes to work w/o magic cookies")); 445 } 446 447 if (magic_cookie_glitch > 0) { /* tvi, wyse */ 448 449 SP->_xmc_triggers = SP->_ok_attributes & ( 450 A_STANDOUT | 451 A_UNDERLINE | 452 A_REVERSE | 453 A_BLINK | 454 A_DIM | 455 A_BOLD | 456 A_INVIS | 457 A_PROTECT 458 ); 459 #if 0 460 /* 461 * We "should" treat colors as an attribute. The wyse350 (and its 462 * clones) appear to be the only ones that have both colors and magic 463 * cookies. 464 */ 465 if (has_colors()) { 466 SP->_xmc_triggers |= A_COLOR; 467 } 468 #endif 469 SP->_xmc_suppress = SP->_xmc_triggers & (chtype) ~(A_BOLD); 470 471 T(("magic cookie attributes %s", _traceattr(SP->_xmc_suppress))); 472 /* 473 * Supporting line-drawing may be possible. But make the regular 474 * video attributes work first. 475 */ 476 acs_chars = ABSENT_STRING; 477 ena_acs = ABSENT_STRING; 478 enter_alt_charset_mode = ABSENT_STRING; 479 exit_alt_charset_mode = ABSENT_STRING; 480 #if USE_XMC_SUPPORT 481 /* 482 * To keep the cookie support simple, suppress all of the optimization 483 * hooks except for clear_screen and the cursor addressing. 484 */ 485 if (support_cookies) { 486 clr_eol = ABSENT_STRING; 487 clr_eos = ABSENT_STRING; 488 set_attributes = ABSENT_STRING; 489 } 490 #endif 491 } else if (magic_cookie_glitch == 0) { /* hpterm */ 492 } 493 494 /* 495 * If magic cookies are not supported, cancel the strings that set 496 * video attributes. 497 */ 498 if (!support_cookies && magic_cookie_glitch >= 0) { 499 magic_cookie_glitch = ABSENT_NUMERIC; 500 set_attributes = ABSENT_STRING; 501 enter_blink_mode = ABSENT_STRING; 502 enter_bold_mode = ABSENT_STRING; 503 enter_dim_mode = ABSENT_STRING; 504 enter_reverse_mode = ABSENT_STRING; 505 enter_standout_mode = ABSENT_STRING; 506 enter_underline_mode = ABSENT_STRING; 507 } 508 509 /* initialize normal acs before wide, since we use mapping in the latter */ 510 #if !USE_WIDEC_SUPPORT 511 if (_nc_unicode_locale() && _nc_locale_breaks_acs(cur_term)) { 512 acs_chars = NULL; 513 ena_acs = NULL; 514 enter_alt_charset_mode = NULL; 515 exit_alt_charset_mode = NULL; 516 set_attributes = NULL; 517 } 518 #endif 519 _nc_init_acs(); 520 #if USE_WIDEC_SUPPORT 521 _nc_init_wacs(); 522 523 SP->_screen_acs_fix = (_nc_unicode_locale() 524 && _nc_locale_breaks_acs(cur_term)); 525 #endif 526 env = _nc_get_locale(); 527 SP->_legacy_coding = ((env == 0) 528 || !strcmp(env, "C") 529 || !strcmp(env, "POSIX")); 530 T(("legacy-coding %d", SP->_legacy_coding)); 531 532 _nc_idcok = TRUE; 533 _nc_idlok = FALSE; 534 535 SP->oldhash = 0; 536 SP->newhash = 0; 537 538 T(("creating newscr")); 539 if ((SP->_newscr = newwin(slines, scolumns, 0, 0)) == 0) 540 returnCode(ERR); 541 542 T(("creating curscr")); 543 if ((SP->_curscr = newwin(slines, scolumns, 0, 0)) == 0) 544 returnCode(ERR); 545 546 #if !USE_REENTRANT 547 newscr = SP->_newscr; 548 curscr = SP->_curscr; 549 #endif 550 #if USE_SIZECHANGE 551 SP->_resize = resizeterm; 552 #endif 553 554 newscr->_clear = TRUE; 555 curscr->_clear = FALSE; 556 557 def_shell_mode(); 558 def_prog_mode(); 559 560 for (rop = ripoff_stack; 561 rop != ripoff_sp && (rop - ripoff_stack) < N_RIPS; 562 rop++) { 563 564 /* If we must simulate soft labels, grab off the line to be used. 565 We assume that we must simulate, if it is none of the standard 566 formats (4-4 or 3-2-3) for which there may be some hardware 567 support. */ 568 if (rop->hook == _nc_slk_initialize) 569 if (!(num_labels <= 0 || !SLK_STDFMT(slk_format))) 570 continue; 571 if (rop->hook) { 572 int count; 573 WINDOW *w; 574 575 count = (rop->line < 0) ? -rop->line : rop->line; 576 T(("ripping off %i lines at %s", count, 577 ((rop->line < 0) 578 ? "bottom" 579 : "top"))); 580 581 w = newwin(count, scolumns, 582 ((rop->line < 0) 583 ? SP->_lines_avail - count 584 : 0), 585 0); 586 if (w) { 587 rop->win = w; 588 rop->hook(w, scolumns); 589 } else { 590 returnCode(ERR); 591 } 592 if (rop->line < 0) 593 bottom_stolen += count; 594 else 595 SP->_topstolen += count; 596 SP->_lines_avail -= count; 597 } 598 } 599 /* reset the stack */ 600 ripoff_sp = ripoff_stack; 601 602 T(("creating stdscr")); 603 assert((SP->_lines_avail + SP->_topstolen + bottom_stolen) == slines); 604 if ((SP->_stdscr = newwin(SP->_lines_avail, scolumns, 0, 0)) == 0) 605 returnCode(ERR); 606 607 SET_LINES(SP->_lines_avail); 608 #if !USE_REENTRANT 609 stdscr = SP->_stdscr; 610 #endif 611 612 returnCode(OK); 613 } 614 615 /* 616 * The internal implementation interprets line as the number of lines to rip 617 * off from the top or bottom. 618 */ 619 NCURSES_EXPORT(int) 620 _nc_ripoffline(int line, int (*init) (WINDOW *, int)) 621 { 622 T((T_CALLED("_nc_ripoffline(%d, %p)"), line, init)); 623 624 if (line != 0) { 625 626 if (ripoff_sp == 0) 627 ripoff_sp = ripoff_stack; 628 if (ripoff_sp >= ripoff_stack + N_RIPS) 629 returnCode(ERR); 630 631 ripoff_sp->line = line; 632 ripoff_sp->hook = init; 633 ripoff_sp++; 634 } 635 636 returnCode(OK); 637 } 638 639 NCURSES_EXPORT(int) 640 ripoffline(int line, int (*init) (WINDOW *, int)) 641 { 642 START_TRACE(); 643 T((T_CALLED("ripoffline(%d,%p)"), line, init)); 644 645 if (line == 0) 646 returnCode(OK); 647 648 returnCode(_nc_ripoffline((line < 0) ? -1 : 1, init)); 649 } 650