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