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