ncurses 4.2
[ncurses.git] / ncurses / lib_set_term.c
1 /****************************************************************************
2  * Copyright (c) 1998 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  ****************************************************************************/
33
34
35
36 /*
37 **      lib_set_term.c
38 **
39 **      The routine set_term().
40 **
41 */
42
43 #include <curses.priv.h>
44
45 #include <term.h>       /* cur_term */
46
47 MODULE_ID("$Id: lib_set_term.c,v 1.37 1998/02/11 12:13:57 tom Exp $")
48
49 /*
50  * If the output file descriptor is connected to a tty (the typical case) it
51  * will probably be line-buffered.  Keith Bostic pointed out that we don't want
52  * this; it hoses people running over networks by forcing out a bunch of small
53  * packets instead of one big one, so screen updates on ptys look jerky. 
54  * Restore block buffering to prevent this minor lossage.
55  *
56  * The buffer size is a compromise.  Ideally we'd like a buffer that can hold
57  * the maximum possible update size (the whole screen plus cup commands to
58  * change lines as it's painted).  On a 66-line xterm this can become
59  * excessive.  So we min it with the amount of data we think we can get through
60  * two Ethernet packets (maximum packet size - 100 for TCP/IP overhead).
61  *
62  * Why two ethernet packets?  It used to be one, on the theory that said
63  * packets define the maximum size of atomic update.  But that's less than the
64  * 2000 chars on a 25 x 80 screen, and we don't want local updates to flicker
65  * either.  Two packet lengths will handle up to a 35 x 80 screen.
66  *
67  * The magic '6' is the estimated length of the end-of-line cup sequence to go
68  * to the next line.  It's generous.  We used to mess with the buffering in
69  * init_mvcur() after cost computation, but that lost the sequences emitted by
70  * init_acs() in setupscreen().
71  *
72  * "The setvbuf function may be used only after the stream pointed to by stream
73  * has been associated with an open file and before any other operation is
74  * performed on the stream." (ISO 7.9.5.6.)
75  *
76  * Grrrr...
77  */
78 void _nc_set_buffer(FILE *ofp, bool buffered)
79 {
80         /* optional optimization hack -- do before any output to ofp */
81 #if HAVE_SETVBUF || HAVE_SETBUFFER  
82         unsigned buf_len;
83         char *buf_ptr;
84
85         if (buffered) {
86                 buf_len = min(LINES * (COLS + 6), 2800);
87                 buf_ptr = malloc(buf_len);
88         } else {
89                 buf_len = 0;
90                 buf_ptr = 0;
91         }
92
93 #if HAVE_SETVBUF
94 #ifdef SETVBUF_REVERSED /* pre-svr3? */
95         (void) setvbuf(ofp, buf_ptr, buf_len, buf_len ? _IOFBF : _IONBF);
96 #else
97         (void) setvbuf(ofp, buf_ptr, buf_len ? _IOFBF : _IONBF, buf_len);
98 #endif
99 #elif HAVE_SETBUFFER
100         (void) setbuffer(ofp, buf_ptr, (int)buf_len);
101 #endif
102
103         if (!buffered) {
104                 FreeIfNeeded(SP->_setbuf);
105         }
106         SP->_setbuf = buf_ptr;
107
108 #endif /* HAVE_SETVBUF || HAVE_SETBUFFER */
109 }
110
111 SCREEN * set_term(SCREEN *screen)
112 {
113 SCREEN  *oldSP;
114
115         T((T_CALLED("set_term(%p)"), screen));
116
117         oldSP = SP;
118         _nc_set_screen(screen);
119
120         set_curterm(SP->_term);
121         curscr      = SP->_curscr;
122         newscr      = SP->_newscr;
123         stdscr      = SP->_stdscr;
124         COLORS      = SP->_color_count;
125         COLOR_PAIRS = SP->_pair_count;
126         memcpy(acs_map, SP->_acs_map, sizeof(chtype)*ACS_LEN);
127
128         T((T_RETURN("%p"), oldSP));
129         return(oldSP);
130 }
131
132 static void _nc_free_keytry(struct tries *kt)
133 {
134         if (kt != 0) {
135                 _nc_free_keytry(kt->child);
136                 _nc_free_keytry(kt->sibling);
137                 free(kt);
138         }
139 }
140
141 /*
142  * Free the storage associated with the given SCREEN sp.
143  */
144 void delscreen(SCREEN *sp)
145 {
146         SCREEN **scan = &_nc_screen_chain;
147
148         T((T_CALLED("delscreen(%p)"), sp));
149
150         while(*scan)
151         {
152             if (*scan == sp)
153             {
154                 *scan = sp->_next_screen;
155                 break;
156             }
157             scan = &(*scan)->_next_screen;
158         }
159
160         _nc_freewin(sp->_curscr);
161         _nc_freewin(sp->_newscr);
162         _nc_freewin(sp->_stdscr);
163         _nc_free_keytry(sp->_keytry);
164         _nc_free_keytry(sp->_key_ok);
165
166         FreeIfNeeded(sp->_color_table);
167         FreeIfNeeded(sp->_color_pairs);
168
169         free(sp);
170
171         /*
172          * If this was the current screen, reset everything that the
173          * application might try to use (except cur_term, which may have
174          * multiple references in different screens).
175          */
176         if (sp == SP) {
177                 curscr = 0;
178                 newscr = 0;
179                 stdscr = 0;
180                 COLORS = 0;
181                 COLOR_PAIRS = 0;
182                 _nc_set_screen(0);
183         }
184         returnVoid;
185 }
186
187 static ripoff_t rippedoff[5];
188 static ripoff_t *rsp = rippedoff;
189 #define N_RIPS SIZEOF(rippedoff)
190
191 static bool no_mouse_event (SCREEN *sp GCC_UNUSED) { return FALSE; }
192 static bool no_mouse_inline(SCREEN *sp GCC_UNUSED) { return FALSE; }
193 static bool no_mouse_parse (int code   GCC_UNUSED) { return TRUE; }
194 static void no_mouse_resume(SCREEN *sp GCC_UNUSED) { }
195 static void no_mouse_wrap  (SCREEN *sp GCC_UNUSED) { }
196
197 int _nc_setupscreen(short slines, short const scolumns, FILE *output)
198 /* OS-independent screen initializations */
199 {
200 int     bottom_stolen = 0;
201 size_t  i;
202
203         assert(SP==0); /* has been reset in newterm() ! */ 
204         if (!_nc_alloc_screen())
205                 return ERR;
206
207         SP->_next_screen = _nc_screen_chain;
208         _nc_screen_chain = SP;
209         
210         _nc_set_buffer(output, TRUE);
211         SP->_term        = cur_term;
212         SP->_lines       = slines;
213         SP->_lines_avail = slines;
214         SP->_columns     = scolumns;
215         SP->_cursrow     = -1;
216         SP->_curscol     = -1;
217         SP->_nl          = TRUE;
218         SP->_raw         = FALSE;
219         SP->_cbreak      = FALSE;
220         SP->_echo        = TRUE;
221         SP->_fifohead    = -1;
222         SP->_endwin      = TRUE;
223         SP->_ofp         = output;
224         SP->_cursor      = -1;  /* cannot know real cursor shape */
225
226         SP->_maxclick     = DEFAULT_MAXCLICK;
227         SP->_mouse_event  = no_mouse_event;
228         SP->_mouse_inline = no_mouse_inline;
229         SP->_mouse_parse  = no_mouse_parse;
230         SP->_mouse_resume = no_mouse_resume;
231         SP->_mouse_wrap   = no_mouse_wrap;
232         SP->_mouse_fd     = -1;
233
234         /* initialize the panel hooks */
235         SP->_panelHook.top_panel = (struct panel*)0;
236         SP->_panelHook.bottom_panel = (struct panel*)0;
237         SP->_panelHook.stdscr_pseudo_panel = (struct panel*)0;
238
239         /*
240          * If we've no magic cookie support, we suppress attributes that xmc
241          * would affect, i.e., the attributes that affect the rendition of a
242          * space.  Note that this impacts the alternate character set mapping
243          * as well.
244          */
245         if (magic_cookie_glitch > 0) {
246
247                 SP->_xmc_triggers = termattrs() & (
248                                 A_ALTCHARSET |
249                                 A_BLINK |
250                                 A_BOLD |
251                                 A_REVERSE |
252                                 A_STANDOUT |
253                                 A_UNDERLINE
254                                 );
255                 SP->_xmc_suppress = SP->_xmc_triggers & (chtype)~(A_BOLD);
256
257                 T(("magic cookie attributes %s", _traceattr(SP->_xmc_suppress)));
258 #if USE_XMC_SUPPORT
259                 /*
260                  * To keep this simple, suppress all of the optimization hooks
261                  * except for clear_screen and the cursor addressing.
262                  */
263                 clr_eol = 0;
264                 clr_eos = 0;
265                 set_attributes = 0;
266 #else
267                 magic_cookie_glitch = -1;
268                 acs_chars = 0;
269 #endif
270         }
271         init_acs();
272         memcpy(SP->_acs_map, acs_map, sizeof(chtype)*ACS_LEN);
273
274         _nc_idcok = TRUE;
275         _nc_idlok = FALSE;
276         
277         _nc_windows = 0; /* no windows yet */
278
279         T(("creating newscr"));
280         if ((newscr = newwin(slines, scolumns, 0, 0)) == 0)
281                 return ERR;
282
283         T(("creating curscr"));
284         if ((curscr = newwin(slines, scolumns, 0, 0)) == 0)
285                 return ERR;
286
287         SP->_newscr = newscr;
288         SP->_curscr = curscr;
289 #if USE_SIZECHANGE
290         SP->_resize = resizeterm;
291 #endif
292
293         newscr->_clear = TRUE;
294         curscr->_clear = FALSE;
295
296         for (i=0, rsp = rippedoff; rsp->line && (i < N_RIPS); rsp++, i++) {
297           if (rsp->hook) {
298               WINDOW *w;
299               int count = (rsp->line < 0) ? -rsp->line : rsp->line;
300
301               if (rsp->line < 0) {
302                   w = newwin(count,scolumns,SP->_lines_avail - count,0);
303                   if (w) {
304                       rsp->w = w;
305                       rsp->hook(w, scolumns);
306                       bottom_stolen += count;
307                   }
308                   else
309                     return ERR;
310               } else {
311                   w = newwin(count,scolumns, 0, 0);
312                   if (w) {
313                       rsp->w = w;
314                       rsp->hook(w, scolumns);
315                       SP->_topstolen += count;
316                   }
317                   else
318                     return ERR;
319               }
320               SP->_lines_avail -= count;
321           }
322           rsp->line = 0;
323         }
324         /* reset the stack */
325         rsp = rippedoff;
326
327         T(("creating stdscr"));
328         assert ((SP->_lines_avail + SP->_topstolen + bottom_stolen) == slines);
329         if ((stdscr = newwin(LINES = SP->_lines_avail, scolumns, 0, 0)) == 0)
330                 return ERR;
331         SP->_stdscr = stdscr;
332
333         def_shell_mode();
334         def_prog_mode();
335
336         return OK;
337 }
338
339 /* The internal implementation interprets line as the number of
340    lines to rip off from the top or bottom.
341    */
342 int
343 _nc_ripoffline(int line, int (*init)(WINDOW *,int))
344 {
345     if (line == 0)
346         return(OK);
347
348     if (rsp >= rippedoff + N_RIPS)
349         return(ERR);
350
351     rsp->line = line;
352     rsp->hook = init;
353     rsp->w    = 0;
354     rsp++;
355
356     return(OK);
357 }
358
359 int
360 ripoffline(int line, int (*init)(WINDOW *, int))
361 {
362     T((T_CALLED("ripoffline(%d,%p)"), line, init));
363
364     if (line == 0)
365         returnCode(OK);
366
367     returnCode(_nc_ripoffline ((line<0) ? -1 : 1, init));
368 }