ncurses 4.1
[ncurses.git] / ncurses / lib_set_term.c
1
2 /***************************************************************************
3 *                            COPYRIGHT NOTICE                              *
4 ****************************************************************************
5 *                ncurses is copyright (C) 1992-1995                        *
6 *                          Zeyd M. Ben-Halim                               *
7 *                          zmbenhal@netcom.com                             *
8 *                          Eric S. Raymond                                 *
9 *                          esr@snark.thyrsus.com                           *
10 *                                                                          *
11 *        Permission is hereby granted to reproduce and distribute ncurses  *
12 *        by any means and for any fee, whether alone or as part of a       *
13 *        larger distribution, in source or in binary form, PROVIDED        *
14 *        this notice is included with any such distribution, and is not    *
15 *        removed from any of its header files. Mention of ncurses in any   *
16 *        applications linked with it is highly appreciated.                *
17 *                                                                          *
18 *        ncurses comes AS IS with no warranty, implied or expressed.       *
19 *                                                                          *
20 ***************************************************************************/
21
22
23
24 /*
25 **      lib_set_term.c
26 **
27 **      The routine set_term().
28 **
29 */
30
31 #include <curses.priv.h>
32
33 #include <term.h>       /* cur_term */
34
35 MODULE_ID("$Id: lib_set_term.c,v 1.17 1997/05/01 23:46:18 Alexander.V.Lukyanov Exp $")
36
37 /*
38  * If the output file descriptor is connected to a tty (the typical case) it
39  * will probably be line-buffered.  Keith Bostic pointed out that we don't want
40  * this; it hoses people running over networks by forcing out a bunch of small
41  * packets instead of one big one, so screen updates on ptys look jerky. 
42  * Restore block buffering to prevent this minor lossage.
43  *
44  * The buffer size is a compromise.  Ideally we'd like a buffer that can hold
45  * the maximum possible update size (the whole screen plus cup commands to
46  * change lines as it's painted).  On a 66-line xterm this can become
47  * excessive.  So we min it with the amount of data we think we can get through
48  * two Ethernet packets (maximum packet size - 100 for TCP/IP overhead).
49  *
50  * Why two ethernet packets?  It used to be one, on the theory that said
51  * packets define the maximum size of atomic update.  But that's less than the
52  * 2000 chars on a 25 x 80 screen, and we don't want local updates to flicker
53  * either.  Two packet lengths will handle up to a 35 x 80 screen.
54  *
55  * The magic '6' is the estimated length of the end-of-line cup sequence to go
56  * to the next line.  It's generous.  We used to mess with the buffering in
57  * init_mvcur() after cost computation, but that lost the sequences emitted by
58  * init_acs() in setupscreen().
59  *
60  * "The setvbuf function may be used only after the stream pointed to by stream
61  * has been associated with an open file and before any other operation is
62  * performed on the stream." (ISO 7.9.5.6.)
63  *
64  * Grrrr...
65  */
66 void _nc_set_buffer(FILE *ofp, bool buffered)
67 {
68         /* optional optimization hack -- do before any output to ofp */
69 #if HAVE_SETVBUF || HAVE_SETBUFFER  
70         unsigned buf_len;
71         char *buf_ptr;
72
73         if (buffered) {
74                 buf_len = min(LINES * (COLS + 6), 2800);
75                 buf_ptr = malloc(buf_len);
76         } else {
77                 buf_len = 0;
78                 buf_ptr = 0;
79         }
80
81 #if HAVE_SETVBUF
82 #ifdef SETVBUF_REVERSED /* pre-svr3? */
83         (void) setvbuf(ofp, buf_ptr, buf_len, buf_len ? _IOFBF : _IONBF);
84 #else
85         (void) setvbuf(ofp, buf_ptr, buf_len ? _IOFBF : _IONBF, buf_len);
86 #endif
87 #elif HAVE_SETBUFFER
88         (void) setbuffer(ofp, buf_ptr, (int)buf_len);
89 #endif
90
91         if (!buffered) {
92                 FreeIfNeeded(SP->_setbuf);
93         }
94         SP->_setbuf = buf_ptr;
95
96 #endif /* HAVE_SETVBUF || HAVE_SETBUFFER */
97 }
98
99 SCREEN * set_term(SCREEN *screen)
100 {
101 SCREEN  *oldSP;
102
103         T((T_CALLED("set_term(%p)"), screen));
104
105         oldSP = SP;
106         _nc_set_screen(screen);
107
108         cur_term    = SP->_term;
109         curscr      = SP->_curscr;
110         newscr      = SP->_newscr;
111         stdscr      = SP->_stdscr;
112         COLORS      = SP->_color_count;
113         COLOR_PAIRS = SP->_pair_count;
114
115         T((T_RETURN("%p"), oldSP));
116         return(oldSP);
117 }
118
119 static void _nc_free_keytry(struct tries *kt)
120 {
121         if (kt != 0) {
122                 _nc_free_keytry(kt->child);
123                 _nc_free_keytry(kt->sibling);
124                 free(kt);
125         }
126 }
127
128 /*
129  * Free the storage associated with the given SCREEN sp.
130  */
131 void delscreen(SCREEN *sp)
132 {
133         T((T_CALLED("delscreen(%p)"), sp));
134
135         _nc_freewin(sp->_curscr);
136         _nc_freewin(sp->_newscr);
137         _nc_freewin(sp->_stdscr);
138         _nc_free_keytry(sp->_keytry);
139
140         FreeIfNeeded(sp->_color_table);
141         FreeIfNeeded(sp->_color_pairs);
142
143         free(sp);
144
145         /*
146          * If this was the current screen, reset everything that the
147          * application might try to use (except cur_term, which may have
148          * multiple references in different screens).
149          */
150         if (sp == SP) {
151                 curscr = 0;
152                 newscr = 0;
153                 stdscr = 0;
154                 COLORS = 0;
155                 COLOR_PAIRS = 0;
156                 _nc_set_screen(0);
157         }
158         returnVoid;
159 }
160
161 ripoff_t rippedoff[5], *rsp = rippedoff;
162 #define N_RIPS (int)(sizeof(rippedoff)/sizeof(rippedoff[0]))
163
164 int _nc_setupscreen(short slines, short const scolumns, FILE *output)
165 /* OS-independent screen initializations */
166 {
167 int     bottom_stolen = 0, i;
168
169         if (!_nc_alloc_screen())
170                 return ERR;
171
172         _nc_set_buffer(output, TRUE);
173         SP->_term        = cur_term;
174         SP->_lines       = slines;
175         SP->_lines_avail = slines;
176         SP->_columns     = scolumns;
177         SP->_cursrow     = -1;
178         SP->_curscol     = -1;
179         SP->_keytry      = UNINITIALISED;
180         SP->_nl          = TRUE;
181         SP->_raw         = FALSE;
182         SP->_cbreak      = FALSE;
183         SP->_echo        = FALSE;
184         SP->_fifohead    = -1;
185         SP->_fifotail    = 0;
186         SP->_fifopeek    = 0;
187         SP->_endwin      = TRUE;
188         SP->_ofp         = output;
189         SP->_coloron     = 0;
190         SP->_curscr      = 0;
191         SP->_newscr      = 0;
192         SP->_stdscr      = 0;
193         SP->_topstolen   = 0;
194         SP->_cursor      = -1;  /* cannot know real cursor shape */
195
196         init_acs();
197
198         T(("creating newscr"));
199         if ((newscr = newwin(slines, scolumns, 0, 0)) == 0)
200                 return ERR;
201
202         T(("creating curscr"));
203         if ((curscr = newwin(slines, scolumns, 0, 0)) == 0)
204                 return ERR;
205
206         SP->_newscr = newscr;
207         SP->_curscr = curscr;
208
209         newscr->_clear = TRUE;
210         curscr->_clear = FALSE;
211
212         for (i=0, rsp = rippedoff; rsp->line && (i < N_RIPS); rsp++, i++) {
213           if (rsp->hook) {
214               WINDOW *w;
215               int count = (rsp->line < 0) ? -rsp->line : rsp->line;
216
217               if (rsp->line < 0) {
218                   w = newwin(count,scolumns,SP->_lines_avail - count,0);
219                   if (w) {
220                       rsp->w = w;
221                       rsp->hook(w, scolumns);
222                       bottom_stolen += count;
223                   }
224                   else
225                     return ERR;
226               } else {
227                   w = newwin(count,scolumns, 0, 0);
228                   if (w) {
229                       rsp->w = w;
230                       rsp->hook(w, scolumns);
231                       SP->_topstolen += count;
232                   }
233                   else
234                     return ERR;
235               }
236               SP->_lines_avail -= count;
237           }
238         }
239
240         T(("creating stdscr"));
241         assert ((SP->_lines_avail + SP->_topstolen + bottom_stolen) == slines);
242         if ((stdscr = newwin(LINES = SP->_lines_avail, scolumns, 0, 0)) == 0)
243                 return ERR;
244         SP->_stdscr = stdscr;
245
246         def_shell_mode();
247         def_prog_mode();
248
249         return OK;
250 }
251
252 /* The internal implementation interprets line as the number of
253    lines to rip off from the top or bottom.
254    */
255 int
256 _nc_ripoffline(int line, int (*init)(WINDOW *,int))
257 {
258     if (line == 0)
259         return(OK);
260
261     if (rsp >= rippedoff + N_RIPS)
262         return(ERR);
263
264     rsp->line = line;
265     rsp->hook = init;
266     rsp->w    = 0;
267     rsp++;
268
269     return(OK);
270 }
271
272 int
273 ripoffline(int line, int (*init)(WINDOW *, int))
274 {
275     T((T_CALLED("ripoffline(%d,%p)"), line, init));
276
277     if (line == 0)
278         returnCode(OK);
279
280     returnCode(_nc_ripoffline ((line<0) ? -1 : 1, init));
281 }