xref: /freebsd/contrib/nvi/vi/vs_split.c (revision 110d525ec6188f3c9dc4f54c4bc1cced2f7184cd)
1b8ba871bSPeter Wemm /*-
2b8ba871bSPeter Wemm  * Copyright (c) 1993, 1994
3b8ba871bSPeter Wemm  *	The Regents of the University of California.  All rights reserved.
4b8ba871bSPeter Wemm  * Copyright (c) 1993, 1994, 1995, 1996
5b8ba871bSPeter Wemm  *	Keith Bostic.  All rights reserved.
6b8ba871bSPeter Wemm  *
7b8ba871bSPeter Wemm  * See the LICENSE file for redistribution information.
8b8ba871bSPeter Wemm  */
9b8ba871bSPeter Wemm 
10b8ba871bSPeter Wemm #include "config.h"
11b8ba871bSPeter Wemm 
12b8ba871bSPeter Wemm #include <sys/types.h>
13b8ba871bSPeter Wemm #include <sys/queue.h>
14b8ba871bSPeter Wemm #include <sys/time.h>
15b8ba871bSPeter Wemm 
16b8ba871bSPeter Wemm #include <bitstring.h>
17b8ba871bSPeter Wemm #include <errno.h>
18b8ba871bSPeter Wemm #include <limits.h>
19b8ba871bSPeter Wemm #include <stdio.h>
20b8ba871bSPeter Wemm #include <stdlib.h>
21b8ba871bSPeter Wemm #include <string.h>
22b8ba871bSPeter Wemm 
23b8ba871bSPeter Wemm #include "../common/common.h"
24b8ba871bSPeter Wemm #include "vi.h"
25b8ba871bSPeter Wemm 
26f0957ccaSPeter Wemm typedef enum { HORIZ_FOLLOW, HORIZ_PRECEDE, VERT_FOLLOW, VERT_PRECEDE } jdir_t;
27f0957ccaSPeter Wemm 
28c271fa92SBaptiste Daroussin static SCR	*vs_getbg(SCR *, char *);
29c271fa92SBaptiste Daroussin static void      vs_insert(SCR *sp, GS *gp);
30c271fa92SBaptiste Daroussin static int	 vs_join(SCR *, SCR **, jdir_t *);
31b8ba871bSPeter Wemm 
32b8ba871bSPeter Wemm /*
33b8ba871bSPeter Wemm  * vs_split --
34f0957ccaSPeter Wemm  *	Create a new screen, horizontally.
35b8ba871bSPeter Wemm  *
36c271fa92SBaptiste Daroussin  * PUBLIC: int vs_split(SCR *, SCR *, int);
37b8ba871bSPeter Wemm  */
38b8ba871bSPeter Wemm int
vs_split(SCR * sp,SCR * new,int ccl)39f0957ccaSPeter Wemm vs_split(
40f0957ccaSPeter Wemm 	SCR *sp,
41f0957ccaSPeter Wemm 	SCR *new,
42f0957ccaSPeter Wemm 	int ccl)		/* Colon-command line split. */
43b8ba871bSPeter Wemm {
44b8ba871bSPeter Wemm 	GS *gp;
45b8ba871bSPeter Wemm 	SMAP *smp;
46b8ba871bSPeter Wemm 	size_t half;
47b8ba871bSPeter Wemm 	int issmallscreen, splitup;
48b8ba871bSPeter Wemm 
49b8ba871bSPeter Wemm 	gp = sp->gp;
50b8ba871bSPeter Wemm 
51b8ba871bSPeter Wemm 	/* Check to see if it's possible. */
52b8ba871bSPeter Wemm 	/* XXX: The IS_ONELINE fix will change this, too. */
53b8ba871bSPeter Wemm 	if (sp->rows < 4) {
54b8ba871bSPeter Wemm 		msgq(sp, M_ERR,
55b8ba871bSPeter Wemm 		    "222|Screen must be larger than %d lines to split", 4 - 1);
56b8ba871bSPeter Wemm 		return (1);
57b8ba871bSPeter Wemm 	}
58b8ba871bSPeter Wemm 
59b8ba871bSPeter Wemm 	/* Wait for any messages in the screen. */
60b8ba871bSPeter Wemm 	vs_resolve(sp, NULL, 1);
61b8ba871bSPeter Wemm 
62b8ba871bSPeter Wemm 	/* Get a new screen map. */
63*110d525eSBaptiste Daroussin 	CALLOC(sp, _HMAP(new), SIZE_HMAP(sp), sizeof(SMAP));
64b8ba871bSPeter Wemm 	if (_HMAP(new) == NULL)
65b8ba871bSPeter Wemm 		return (1);
66b8ba871bSPeter Wemm 	_HMAP(new)->lno = sp->lno;
67b8ba871bSPeter Wemm 	_HMAP(new)->coff = 0;
68b8ba871bSPeter Wemm 	_HMAP(new)->soff = 1;
69b8ba871bSPeter Wemm 
70f0957ccaSPeter Wemm 	/* Split the screen in half. */
71f0957ccaSPeter Wemm 	half = sp->rows / 2;
72f0957ccaSPeter Wemm 	if (ccl && half > 6)
73f0957ccaSPeter Wemm 		half = 6;
74f0957ccaSPeter Wemm 
75b8ba871bSPeter Wemm 	/*
76b8ba871bSPeter Wemm 	 * Small screens: see vs_refresh.c section 6a.  Set a flag so
77b8ba871bSPeter Wemm 	 * we know to fix the screen up later.
78b8ba871bSPeter Wemm 	 */
79b8ba871bSPeter Wemm 	issmallscreen = IS_SMALL(sp);
80b8ba871bSPeter Wemm 
81b8ba871bSPeter Wemm 	/* The columns in the screen don't change. */
82f0957ccaSPeter Wemm 	new->coff = sp->coff;
83b8ba871bSPeter Wemm 	new->cols = sp->cols;
84b8ba871bSPeter Wemm 
85b8ba871bSPeter Wemm 	/*
86b8ba871bSPeter Wemm 	 * Split the screen, and link the screens together.  If creating a
87b8ba871bSPeter Wemm 	 * screen to edit the colon command line or the cursor is in the top
88b8ba871bSPeter Wemm 	 * half of the current screen, the new screen goes under the current
89b8ba871bSPeter Wemm 	 * screen.  Else, it goes above the current screen.
90b8ba871bSPeter Wemm 	 *
91b8ba871bSPeter Wemm 	 * Recalculate current cursor position based on sp->lno, we're called
92b8ba871bSPeter Wemm 	 * with the cursor on the colon command line.  Then split the screen
93b8ba871bSPeter Wemm 	 * in half and update the shared information.
94b8ba871bSPeter Wemm 	 */
95b8ba871bSPeter Wemm 	splitup =
96b8ba871bSPeter Wemm 	    !ccl && (vs_sm_cursor(sp, &smp) ? 0 : (smp - HMAP) + 1) >= half;
97b8ba871bSPeter Wemm 	if (splitup) {				/* Old is bottom half. */
98b8ba871bSPeter Wemm 		new->rows = sp->rows - half;	/* New. */
99f0957ccaSPeter Wemm 		new->roff = sp->roff;
100b8ba871bSPeter Wemm 		sp->rows = half;		/* Old. */
101f0957ccaSPeter Wemm 		sp->roff += new->rows;
102b8ba871bSPeter Wemm 
103b8ba871bSPeter Wemm 		/*
104b8ba871bSPeter Wemm 		 * If the parent is the bottom half of the screen, shift
105b8ba871bSPeter Wemm 		 * the map down to match on-screen text.
106b8ba871bSPeter Wemm 		 */
107f0957ccaSPeter Wemm 		memcpy(_HMAP(sp), _HMAP(sp) + new->rows,
108b8ba871bSPeter Wemm 		    (sp->t_maxrows - new->rows) * sizeof(SMAP));
109b8ba871bSPeter Wemm 	} else {				/* Old is top half. */
110b8ba871bSPeter Wemm 		new->rows = half;		/* New. */
111b8ba871bSPeter Wemm 		sp->rows -= half;		/* Old. */
112f0957ccaSPeter Wemm 		new->roff = sp->roff + sp->rows;
113b8ba871bSPeter Wemm 	}
114b8ba871bSPeter Wemm 
115b8ba871bSPeter Wemm 	/* Adjust maximum text count. */
116b8ba871bSPeter Wemm 	sp->t_maxrows = IS_ONELINE(sp) ? 1 : sp->rows - 1;
117b8ba871bSPeter Wemm 	new->t_maxrows = IS_ONELINE(new) ? 1 : new->rows - 1;
118b8ba871bSPeter Wemm 
119b8ba871bSPeter Wemm 	/*
120b8ba871bSPeter Wemm 	 * Small screens: see vs_refresh.c, section 6a.
121b8ba871bSPeter Wemm 	 *
122b8ba871bSPeter Wemm 	 * The child may have different screen options sizes than the parent,
123b8ba871bSPeter Wemm 	 * so use them.  Guarantee that text counts aren't larger than the
124b8ba871bSPeter Wemm 	 * new screen sizes.
125b8ba871bSPeter Wemm 	 */
126b8ba871bSPeter Wemm 	if (issmallscreen) {
127b8ba871bSPeter Wemm 		/* Fix the text line count for the parent. */
128b8ba871bSPeter Wemm 		if (splitup)
129b8ba871bSPeter Wemm 			sp->t_rows -= new->rows;
130b8ba871bSPeter Wemm 
131b8ba871bSPeter Wemm 		/* Fix the parent screen. */
132b8ba871bSPeter Wemm 		if (sp->t_rows > sp->t_maxrows)
133b8ba871bSPeter Wemm 			sp->t_rows = sp->t_maxrows;
134b8ba871bSPeter Wemm 		if (sp->t_minrows > sp->t_maxrows)
135b8ba871bSPeter Wemm 			sp->t_minrows = sp->t_maxrows;
136b8ba871bSPeter Wemm 
137b8ba871bSPeter Wemm 		/* Fix the child screen. */
138b8ba871bSPeter Wemm 		new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW);
139b8ba871bSPeter Wemm 		if (new->t_rows > new->t_maxrows)
140b8ba871bSPeter Wemm 			new->t_rows = new->t_maxrows;
141b8ba871bSPeter Wemm 		if (new->t_minrows > new->t_maxrows)
142b8ba871bSPeter Wemm 			new->t_minrows = new->t_maxrows;
143b8ba871bSPeter Wemm 	} else {
144b8ba871bSPeter Wemm 		sp->t_minrows = sp->t_rows = IS_ONELINE(sp) ? 1 : sp->rows - 1;
145b8ba871bSPeter Wemm 
146b8ba871bSPeter Wemm 		/*
147b8ba871bSPeter Wemm 		 * The new screen may be a small screen, even if the parent
148b8ba871bSPeter Wemm 		 * was not.  Don't complain if O_WINDOW is too large, we're
149b8ba871bSPeter Wemm 		 * splitting the screen so the screen is much smaller than
150b8ba871bSPeter Wemm 		 * normal.
151b8ba871bSPeter Wemm 		 */
152b8ba871bSPeter Wemm 		new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW);
153b8ba871bSPeter Wemm 		if (new->t_rows > new->rows - 1)
154b8ba871bSPeter Wemm 			new->t_minrows = new->t_rows =
155b8ba871bSPeter Wemm 			    IS_ONELINE(new) ? 1 : new->rows - 1;
156b8ba871bSPeter Wemm 	}
157b8ba871bSPeter Wemm 
158b8ba871bSPeter Wemm 	/* Adjust the ends of the new and old maps. */
159b8ba871bSPeter Wemm 	_TMAP(sp) = IS_ONELINE(sp) ?
160b8ba871bSPeter Wemm 	    _HMAP(sp) : _HMAP(sp) + (sp->t_rows - 1);
161b8ba871bSPeter Wemm 	_TMAP(new) = IS_ONELINE(new) ?
162b8ba871bSPeter Wemm 	    _HMAP(new) : _HMAP(new) + (new->t_rows - 1);
163b8ba871bSPeter Wemm 
164b8ba871bSPeter Wemm 	/* Reset the length of the default scroll. */
165b8ba871bSPeter Wemm 	if ((sp->defscroll = sp->t_maxrows / 2) == 0)
166b8ba871bSPeter Wemm 		sp->defscroll = 1;
167b8ba871bSPeter Wemm 	if ((new->defscroll = new->t_maxrows / 2) == 0)
168b8ba871bSPeter Wemm 		new->defscroll = 1;
169b8ba871bSPeter Wemm 
170f0957ccaSPeter Wemm 	/* Fit the screen into the logical chain. */
171f0957ccaSPeter Wemm 	vs_insert(new, sp->gp);
172f0957ccaSPeter Wemm 
173f0957ccaSPeter Wemm 	/* Tell the display that we're splitting. */
174f0957ccaSPeter Wemm 	(void)gp->scr_split(sp, new);
175f0957ccaSPeter Wemm 
176b8ba871bSPeter Wemm 	/*
177b8ba871bSPeter Wemm 	 * Initialize the screen flags:
178b8ba871bSPeter Wemm 	 *
179b8ba871bSPeter Wemm 	 * If we're in vi mode in one screen, we don't have to reinitialize.
180b8ba871bSPeter Wemm 	 * This isn't just a cosmetic fix.  The path goes like this:
181b8ba871bSPeter Wemm 	 *
182b8ba871bSPeter Wemm 	 *	return into vi(), SC_SSWITCH set
183b8ba871bSPeter Wemm 	 *	call vs_refresh() with SC_STATUS set
184b8ba871bSPeter Wemm 	 *	call vs_resolve to display the status message
185b8ba871bSPeter Wemm 	 *	call vs_refresh() because the SC_SCR_VI bit isn't set
186b8ba871bSPeter Wemm 	 *
187b8ba871bSPeter Wemm 	 * Things go downhill at this point.
188b8ba871bSPeter Wemm 	 *
189b8ba871bSPeter Wemm 	 * Draw the new screen from scratch, and add a status line.
190b8ba871bSPeter Wemm 	 */
191b8ba871bSPeter Wemm 	F_SET(new,
192b8ba871bSPeter Wemm 	    SC_SCR_REFORMAT | SC_STATUS |
193c271fa92SBaptiste Daroussin 	    F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX | SC_READONLY));
194b8ba871bSPeter Wemm 	return (0);
195b8ba871bSPeter Wemm }
196b8ba871bSPeter Wemm 
197b8ba871bSPeter Wemm /*
198f0957ccaSPeter Wemm  * vs_vsplit --
199f0957ccaSPeter Wemm  *	Create a new screen, vertically.
200f0957ccaSPeter Wemm  *
201c271fa92SBaptiste Daroussin  * PUBLIC: int vs_vsplit(SCR *, SCR *);
202f0957ccaSPeter Wemm  */
203f0957ccaSPeter Wemm int
vs_vsplit(SCR * sp,SCR * new)204f0957ccaSPeter Wemm vs_vsplit(SCR *sp, SCR *new)
205f0957ccaSPeter Wemm {
206f0957ccaSPeter Wemm 	GS *gp;
207f0957ccaSPeter Wemm 	size_t cols;
208f0957ccaSPeter Wemm 
209f0957ccaSPeter Wemm 	gp = sp->gp;
210f0957ccaSPeter Wemm 
211f0957ccaSPeter Wemm 	/* Check to see if it's possible. */
212f0957ccaSPeter Wemm 	if (sp->cols / 2 <= MINIMUM_SCREEN_COLS) {
213f0957ccaSPeter Wemm 		msgq(sp, M_ERR,
214f0957ccaSPeter Wemm 		    "288|Screen must be larger than %d columns to split",
215f0957ccaSPeter Wemm 		    MINIMUM_SCREEN_COLS * 2);
216f0957ccaSPeter Wemm 		return (1);
217f0957ccaSPeter Wemm 	}
218f0957ccaSPeter Wemm 
219f0957ccaSPeter Wemm 	/* Wait for any messages in the screen. */
220f0957ccaSPeter Wemm 	vs_resolve(sp, NULL, 1);
221f0957ccaSPeter Wemm 
222f0957ccaSPeter Wemm 	/* Get a new screen map. */
223*110d525eSBaptiste Daroussin 	CALLOC(sp, _HMAP(new), SIZE_HMAP(sp), sizeof(SMAP));
224f0957ccaSPeter Wemm 	if (_HMAP(new) == NULL)
225f0957ccaSPeter Wemm 		return (1);
226f0957ccaSPeter Wemm 	_HMAP(new)->lno = sp->lno;
227f0957ccaSPeter Wemm 	_HMAP(new)->coff = 0;
228f0957ccaSPeter Wemm 	_HMAP(new)->soff = 1;
229f0957ccaSPeter Wemm 
230f0957ccaSPeter Wemm 	/*
231f0957ccaSPeter Wemm 	 * Split the screen in half; we have to sacrifice a column to delimit
232f0957ccaSPeter Wemm 	 * the screens.
233f0957ccaSPeter Wemm 	 *
234f0957ccaSPeter Wemm 	 * XXX
235f0957ccaSPeter Wemm 	 * We always split to the right... that makes more sense to me, and
236f0957ccaSPeter Wemm 	 * I don't want to play the stupid games that I play when splitting
237f0957ccaSPeter Wemm 	 * horizontally.
238f0957ccaSPeter Wemm 	 *
239f0957ccaSPeter Wemm 	 * XXX
240f0957ccaSPeter Wemm 	 * We reserve a column for the screen, "knowing" that curses needs
241f0957ccaSPeter Wemm 	 * one.  This should be worked out with the display interface.
242f0957ccaSPeter Wemm 	 */
243f0957ccaSPeter Wemm 	cols = sp->cols / 2;
244f0957ccaSPeter Wemm 	new->cols = sp->cols - cols - 1;
245f0957ccaSPeter Wemm 	sp->cols = cols;
246f0957ccaSPeter Wemm 	new->coff = sp->coff + cols + 1;
247f0957ccaSPeter Wemm 	sp->cno = 0;
248f0957ccaSPeter Wemm 
249f0957ccaSPeter Wemm 	/* Nothing else changes. */
250f0957ccaSPeter Wemm 	new->rows = sp->rows;
251f0957ccaSPeter Wemm 	new->t_rows = sp->t_rows;
252f0957ccaSPeter Wemm 	new->t_maxrows = sp->t_maxrows;
253f0957ccaSPeter Wemm 	new->t_minrows = sp->t_minrows;
254f0957ccaSPeter Wemm 	new->roff = sp->roff;
255f0957ccaSPeter Wemm 	new->defscroll = sp->defscroll;
256f0957ccaSPeter Wemm 	_TMAP(new) = _HMAP(new) + (new->t_rows - 1);
257f0957ccaSPeter Wemm 
258f0957ccaSPeter Wemm 	/* Fit the screen into the logical chain. */
259f0957ccaSPeter Wemm 	vs_insert(new, sp->gp);
260f0957ccaSPeter Wemm 
261f0957ccaSPeter Wemm 	/* Tell the display that we're splitting. */
262f0957ccaSPeter Wemm 	(void)gp->scr_split(sp, new);
263f0957ccaSPeter Wemm 
264f0957ccaSPeter Wemm 	/* Redraw the old screen from scratch. */
265f0957ccaSPeter Wemm 	F_SET(sp, SC_SCR_REFORMAT | SC_STATUS);
266f0957ccaSPeter Wemm 
267f0957ccaSPeter Wemm 	/*
268f0957ccaSPeter Wemm 	 * Initialize the screen flags:
269f0957ccaSPeter Wemm 	 *
270f0957ccaSPeter Wemm 	 * If we're in vi mode in one screen, we don't have to reinitialize.
271f0957ccaSPeter Wemm 	 * This isn't just a cosmetic fix.  The path goes like this:
272f0957ccaSPeter Wemm 	 *
273f0957ccaSPeter Wemm 	 *	return into vi(), SC_SSWITCH set
274f0957ccaSPeter Wemm 	 *	call vs_refresh() with SC_STATUS set
275f0957ccaSPeter Wemm 	 *	call vs_resolve to display the status message
276f0957ccaSPeter Wemm 	 *	call vs_refresh() because the SC_SCR_VI bit isn't set
277f0957ccaSPeter Wemm 	 *
278f0957ccaSPeter Wemm 	 * Things go downhill at this point.
279f0957ccaSPeter Wemm 	 *
280f0957ccaSPeter Wemm 	 * Draw the new screen from scratch, and add a status line.
281f0957ccaSPeter Wemm 	 */
282f0957ccaSPeter Wemm 	F_SET(new,
283f0957ccaSPeter Wemm 	    SC_SCR_REFORMAT | SC_STATUS |
284c271fa92SBaptiste Daroussin 	    F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX | SC_READONLY));
285f0957ccaSPeter Wemm 	return (0);
286f0957ccaSPeter Wemm }
287f0957ccaSPeter Wemm 
288f0957ccaSPeter Wemm /*
289f0957ccaSPeter Wemm  * vs_insert --
290f0957ccaSPeter Wemm  *	Insert the new screen into the correct place in the logical
291f0957ccaSPeter Wemm  *	chain.
292f0957ccaSPeter Wemm  */
293f0957ccaSPeter Wemm static void
vs_insert(SCR * sp,GS * gp)294f0957ccaSPeter Wemm vs_insert(SCR *sp, GS *gp)
295f0957ccaSPeter Wemm {
296f0957ccaSPeter Wemm 	SCR *tsp;
297f0957ccaSPeter Wemm 
298f0957ccaSPeter Wemm 	gp = sp->gp;
299f0957ccaSPeter Wemm 
300f0957ccaSPeter Wemm 	/* Move past all screens with lower row numbers. */
301f0957ccaSPeter Wemm 	TAILQ_FOREACH(tsp, gp->dq, q)
302f0957ccaSPeter Wemm 		if (tsp->roff >= sp->roff)
303f0957ccaSPeter Wemm 			break;
304f0957ccaSPeter Wemm 	/*
305f0957ccaSPeter Wemm 	 * Move past all screens with the same row number and lower
306f0957ccaSPeter Wemm 	 * column numbers.
307f0957ccaSPeter Wemm 	 */
308f0957ccaSPeter Wemm 	for (; tsp != NULL; tsp = TAILQ_NEXT(tsp, q))
309f0957ccaSPeter Wemm 		if (tsp->roff != sp->roff || tsp->coff > sp->coff)
310f0957ccaSPeter Wemm 			break;
311f0957ccaSPeter Wemm 
312f0957ccaSPeter Wemm 	/*
313f0957ccaSPeter Wemm 	 * If we reached the end, this screen goes there.  Otherwise,
314f0957ccaSPeter Wemm 	 * put it before or after the screen where we stopped.
315f0957ccaSPeter Wemm 	 */
316f0957ccaSPeter Wemm 	if (tsp == NULL) {
317f0957ccaSPeter Wemm 		TAILQ_INSERT_TAIL(gp->dq, sp, q);
318f0957ccaSPeter Wemm 	} else if (tsp->roff < sp->roff ||
319f0957ccaSPeter Wemm 	    (tsp->roff == sp->roff && tsp->coff < sp->coff)) {
320f0957ccaSPeter Wemm 		TAILQ_INSERT_AFTER(gp->dq, tsp, sp, q);
321f0957ccaSPeter Wemm 	} else
322f0957ccaSPeter Wemm 		TAILQ_INSERT_BEFORE(tsp, sp, q);
323f0957ccaSPeter Wemm }
324f0957ccaSPeter Wemm 
325f0957ccaSPeter Wemm /*
326b8ba871bSPeter Wemm  * vs_discard --
327b8ba871bSPeter Wemm  *	Discard the screen, folding the real-estate into a related screen,
328b8ba871bSPeter Wemm  *	if one exists, and return that screen.
329b8ba871bSPeter Wemm  *
330c271fa92SBaptiste Daroussin  * PUBLIC: int vs_discard(SCR *, SCR **);
331b8ba871bSPeter Wemm  */
332b8ba871bSPeter Wemm int
vs_discard(SCR * sp,SCR ** spp)333f0957ccaSPeter Wemm vs_discard(SCR *sp, SCR **spp)
334b8ba871bSPeter Wemm {
335f0957ccaSPeter Wemm 	GS *gp;
336f0957ccaSPeter Wemm 	SCR *tsp, **lp, *list[100];
337f0957ccaSPeter Wemm 	jdir_t jdir;
338f0957ccaSPeter Wemm 
339f0957ccaSPeter Wemm 	gp = sp->gp;
340b8ba871bSPeter Wemm 
341b8ba871bSPeter Wemm 	/*
342b8ba871bSPeter Wemm 	 * Save the old screen's cursor information.
343b8ba871bSPeter Wemm 	 *
344b8ba871bSPeter Wemm 	 * XXX
345b8ba871bSPeter Wemm 	 * If called after file_end(), and the underlying file was a tmp
346b8ba871bSPeter Wemm 	 * file, it may have gone away.
347b8ba871bSPeter Wemm 	 */
348b8ba871bSPeter Wemm 	if (sp->frp != NULL) {
349b8ba871bSPeter Wemm 		sp->frp->lno = sp->lno;
350b8ba871bSPeter Wemm 		sp->frp->cno = sp->cno;
351b8ba871bSPeter Wemm 		F_SET(sp->frp, FR_CURSORSET);
352b8ba871bSPeter Wemm 	}
353b8ba871bSPeter Wemm 
354f0957ccaSPeter Wemm 	/* If no other screens to join, we're done. */
355f0957ccaSPeter Wemm 	if (!IS_SPLIT(sp)) {
356f0957ccaSPeter Wemm 		(void)gp->scr_discard(sp, NULL);
357b8ba871bSPeter Wemm 
358b8ba871bSPeter Wemm 		if (spp != NULL)
359f0957ccaSPeter Wemm 			*spp = NULL;
360b8ba871bSPeter Wemm 		return (0);
361f0957ccaSPeter Wemm 	}
362b8ba871bSPeter Wemm 
363b8ba871bSPeter Wemm 	/*
364f0957ccaSPeter Wemm 	 * Find a set of screens that cover one of the screen's borders.
365f0957ccaSPeter Wemm 	 * Check the vertical axis first, for no particular reason.
366b8ba871bSPeter Wemm 	 *
367b8ba871bSPeter Wemm 	 * XXX
368f0957ccaSPeter Wemm 	 * It's possible (I think?), to create a screen that shares no full
369f0957ccaSPeter Wemm 	 * border with any other set of screens, so we can't discard it.  We
370f0957ccaSPeter Wemm 	 * just complain at the user until they clean it up.
371b8ba871bSPeter Wemm 	 */
372f0957ccaSPeter Wemm 	if (vs_join(sp, list, &jdir))
373f0957ccaSPeter Wemm 		return (1);
374f0957ccaSPeter Wemm 
375f0957ccaSPeter Wemm 	/*
376f0957ccaSPeter Wemm 	 * Modify the affected screens.  Redraw the modified screen(s) from
377f0957ccaSPeter Wemm 	 * scratch, setting a status line.  If this is ever a performance
378f0957ccaSPeter Wemm 	 * problem we could play games with the map, but I wrote that code
379f0957ccaSPeter Wemm 	 * before and it was never clean or easy.
380f0957ccaSPeter Wemm 	 *
381f0957ccaSPeter Wemm 	 * Don't clean up the discarded screen's information.  If the screen
382f0957ccaSPeter Wemm 	 * isn't exiting, we'll do the work when the user redisplays it.
383f0957ccaSPeter Wemm 	 */
384f0957ccaSPeter Wemm 	switch (jdir) {
385f0957ccaSPeter Wemm 	case HORIZ_FOLLOW:
386f0957ccaSPeter Wemm 	case HORIZ_PRECEDE:
387f0957ccaSPeter Wemm 		for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) {
388f0957ccaSPeter Wemm 			/*
389f0957ccaSPeter Wemm 			 * Small screens: see vs_refresh.c section 6a.  Adjust
390f0957ccaSPeter Wemm 			 * text line info, unless it's a small screen.
391f0957ccaSPeter Wemm 			 *
392f0957ccaSPeter Wemm 			 * Reset the length of the default scroll.
393f0957ccaSPeter Wemm 			 *
394f0957ccaSPeter Wemm 			 * Reset the map references.
395f0957ccaSPeter Wemm 			 */
396f0957ccaSPeter Wemm 			tsp->rows += sp->rows;
397f0957ccaSPeter Wemm 			if (!IS_SMALL(tsp))
398f0957ccaSPeter Wemm 				tsp->t_rows = tsp->t_minrows = tsp->rows - 1;
399f0957ccaSPeter Wemm 			tsp->t_maxrows = tsp->rows - 1;
400f0957ccaSPeter Wemm 
401f0957ccaSPeter Wemm 			tsp->defscroll = tsp->t_maxrows / 2;
402f0957ccaSPeter Wemm 
403f0957ccaSPeter Wemm 			*(_HMAP(tsp) + (tsp->t_rows - 1)) = *_TMAP(tsp);
404f0957ccaSPeter Wemm 			_TMAP(tsp) = _HMAP(tsp) + (tsp->t_rows - 1);
405f0957ccaSPeter Wemm 
406f0957ccaSPeter Wemm 			switch (jdir) {
407f0957ccaSPeter Wemm 			case HORIZ_FOLLOW:
408f0957ccaSPeter Wemm 				tsp->roff = sp->roff;
409f0957ccaSPeter Wemm 				vs_sm_fill(tsp, OOBLNO, P_TOP);
410b8ba871bSPeter Wemm 				break;
411f0957ccaSPeter Wemm 			case HORIZ_PRECEDE:
412f0957ccaSPeter Wemm 				vs_sm_fill(tsp, OOBLNO, P_BOTTOM);
413f0957ccaSPeter Wemm 				break;
414f0957ccaSPeter Wemm 			default:
415f0957ccaSPeter Wemm 				abort();
416f0957ccaSPeter Wemm 			}
417f0957ccaSPeter Wemm 			F_SET(tsp, SC_STATUS);
418f0957ccaSPeter Wemm 		}
419f0957ccaSPeter Wemm 		break;
420f0957ccaSPeter Wemm 	case VERT_FOLLOW:
421f0957ccaSPeter Wemm 	case VERT_PRECEDE:
422f0957ccaSPeter Wemm 		for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) {
423f0957ccaSPeter Wemm 			if (jdir == VERT_FOLLOW)
424f0957ccaSPeter Wemm 				tsp->coff = sp->coff;
425f0957ccaSPeter Wemm 			tsp->cols += sp->cols + 1;	/* XXX: DIVIDER */
426f0957ccaSPeter Wemm 			vs_sm_fill(tsp, OOBLNO, P_TOP);
427f0957ccaSPeter Wemm 			F_SET(tsp, SC_STATUS);
428f0957ccaSPeter Wemm 		}
429b8ba871bSPeter Wemm 		break;
430b8ba871bSPeter Wemm 	default:
431b8ba871bSPeter Wemm 		abort();
432b8ba871bSPeter Wemm 	}
433b8ba871bSPeter Wemm 
434f0957ccaSPeter Wemm 	/* Find the closest screen that changed and move to it. */
435f0957ccaSPeter Wemm 	tsp = list[0];
436f0957ccaSPeter Wemm 	if (spp != NULL)
437f0957ccaSPeter Wemm 		*spp = tsp;
438f0957ccaSPeter Wemm 
439f0957ccaSPeter Wemm 	/* Tell the display that we're discarding a screen. */
440f0957ccaSPeter Wemm 	(void)gp->scr_discard(sp, list);
441f0957ccaSPeter Wemm 
442b8ba871bSPeter Wemm 	return (0);
443b8ba871bSPeter Wemm }
444b8ba871bSPeter Wemm 
445b8ba871bSPeter Wemm /*
446f0957ccaSPeter Wemm  * vs_join --
447f0957ccaSPeter Wemm  *	Find a set of screens that covers a screen's border.
448f0957ccaSPeter Wemm  */
449f0957ccaSPeter Wemm static int
vs_join(SCR * sp,SCR ** listp,jdir_t * jdirp)450f0957ccaSPeter Wemm vs_join(SCR *sp, SCR **listp, jdir_t *jdirp)
451f0957ccaSPeter Wemm {
452f0957ccaSPeter Wemm 	GS *gp;
453f0957ccaSPeter Wemm 	SCR **lp, *tsp;
454f0957ccaSPeter Wemm 	int first;
455f0957ccaSPeter Wemm 	size_t tlen;
456f0957ccaSPeter Wemm 
457f0957ccaSPeter Wemm 	gp = sp->gp;
458f0957ccaSPeter Wemm 
459f0957ccaSPeter Wemm 	/* Check preceding vertical. */
460f0957ccaSPeter Wemm 	for (lp = listp, tlen = sp->rows,
461f0957ccaSPeter Wemm 	    tsp = TAILQ_FIRST(gp->dq);
462f0957ccaSPeter Wemm 	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
463f0957ccaSPeter Wemm 		if (sp == tsp)
464f0957ccaSPeter Wemm 			continue;
465f0957ccaSPeter Wemm 		/* Test if precedes the screen vertically. */
466f0957ccaSPeter Wemm 		if (tsp->coff + tsp->cols + 1 != sp->coff)
467f0957ccaSPeter Wemm 			continue;
468f0957ccaSPeter Wemm 		/*
469f0957ccaSPeter Wemm 		 * Test if a subset on the vertical axis.  If overlaps the
470f0957ccaSPeter Wemm 		 * beginning or end, we can't join on this axis at all.
471f0957ccaSPeter Wemm 		 */
472f0957ccaSPeter Wemm 		if (tsp->roff > sp->roff + sp->rows)
473f0957ccaSPeter Wemm 			continue;
474f0957ccaSPeter Wemm 		if (tsp->roff < sp->roff) {
475f0957ccaSPeter Wemm 			if (tsp->roff + tsp->rows >= sp->roff)
476f0957ccaSPeter Wemm 				break;
477f0957ccaSPeter Wemm 			continue;
478f0957ccaSPeter Wemm 		}
479f0957ccaSPeter Wemm 		if (tsp->roff + tsp->rows > sp->roff + sp->rows)
480f0957ccaSPeter Wemm 			break;
481f0957ccaSPeter Wemm #ifdef DEBUG
482f0957ccaSPeter Wemm 		if (tlen < tsp->rows)
483f0957ccaSPeter Wemm 			abort();
484f0957ccaSPeter Wemm #endif
485f0957ccaSPeter Wemm 		tlen -= tsp->rows;
486f0957ccaSPeter Wemm 		*lp++ = tsp;
487f0957ccaSPeter Wemm 	}
488f0957ccaSPeter Wemm 	if (tlen == 0) {
489f0957ccaSPeter Wemm 		*lp = NULL;
490f0957ccaSPeter Wemm 		*jdirp = VERT_PRECEDE;
491f0957ccaSPeter Wemm 		return (0);
492f0957ccaSPeter Wemm 	}
493f0957ccaSPeter Wemm 
494f0957ccaSPeter Wemm 	/* Check following vertical. */
495f0957ccaSPeter Wemm 	for (lp = listp, tlen = sp->rows,
496f0957ccaSPeter Wemm 	    tsp = TAILQ_FIRST(gp->dq);
497f0957ccaSPeter Wemm 	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
498f0957ccaSPeter Wemm 		if (sp == tsp)
499f0957ccaSPeter Wemm 			continue;
500f0957ccaSPeter Wemm 		/* Test if follows the screen vertically. */
501f0957ccaSPeter Wemm 		if (tsp->coff != sp->coff + sp->cols + 1)
502f0957ccaSPeter Wemm 			continue;
503f0957ccaSPeter Wemm 		/*
504f0957ccaSPeter Wemm 		 * Test if a subset on the vertical axis.  If overlaps the
505f0957ccaSPeter Wemm 		 * beginning or end, we can't join on this axis at all.
506f0957ccaSPeter Wemm 		 */
507f0957ccaSPeter Wemm 		if (tsp->roff > sp->roff + sp->rows)
508f0957ccaSPeter Wemm 			continue;
509f0957ccaSPeter Wemm 		if (tsp->roff < sp->roff) {
510f0957ccaSPeter Wemm 			if (tsp->roff + tsp->rows >= sp->roff)
511f0957ccaSPeter Wemm 				break;
512f0957ccaSPeter Wemm 			continue;
513f0957ccaSPeter Wemm 		}
514f0957ccaSPeter Wemm 		if (tsp->roff + tsp->rows > sp->roff + sp->rows)
515f0957ccaSPeter Wemm 			break;
516f0957ccaSPeter Wemm #ifdef DEBUG
517f0957ccaSPeter Wemm 		if (tlen < tsp->rows)
518f0957ccaSPeter Wemm 			abort();
519f0957ccaSPeter Wemm #endif
520f0957ccaSPeter Wemm 		tlen -= tsp->rows;
521f0957ccaSPeter Wemm 		*lp++ = tsp;
522f0957ccaSPeter Wemm 	}
523f0957ccaSPeter Wemm 	if (tlen == 0) {
524f0957ccaSPeter Wemm 		*lp = NULL;
525f0957ccaSPeter Wemm 		*jdirp = VERT_FOLLOW;
526f0957ccaSPeter Wemm 		return (0);
527f0957ccaSPeter Wemm 	}
528f0957ccaSPeter Wemm 
529f0957ccaSPeter Wemm 	/* Check preceding horizontal. */
530f0957ccaSPeter Wemm 	for (first = 0, lp = listp, tlen = sp->cols,
531f0957ccaSPeter Wemm 	    tsp = TAILQ_FIRST(gp->dq);
532f0957ccaSPeter Wemm 	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
533f0957ccaSPeter Wemm 		if (sp == tsp)
534f0957ccaSPeter Wemm 			continue;
535f0957ccaSPeter Wemm 		/* Test if precedes the screen horizontally. */
536f0957ccaSPeter Wemm 		if (tsp->roff + tsp->rows != sp->roff)
537f0957ccaSPeter Wemm 			continue;
538f0957ccaSPeter Wemm 		/*
539f0957ccaSPeter Wemm 		 * Test if a subset on the horizontal axis.  If overlaps the
540f0957ccaSPeter Wemm 		 * beginning or end, we can't join on this axis at all.
541f0957ccaSPeter Wemm 		 */
542f0957ccaSPeter Wemm 		if (tsp->coff > sp->coff + sp->cols)
543f0957ccaSPeter Wemm 			continue;
544f0957ccaSPeter Wemm 		if (tsp->coff < sp->coff) {
545f0957ccaSPeter Wemm 			if (tsp->coff + tsp->cols >= sp->coff)
546f0957ccaSPeter Wemm 				break;
547f0957ccaSPeter Wemm 			continue;
548f0957ccaSPeter Wemm 		}
549f0957ccaSPeter Wemm 		if (tsp->coff + tsp->cols > sp->coff + sp->cols)
550f0957ccaSPeter Wemm 			break;
551f0957ccaSPeter Wemm #ifdef DEBUG
552f0957ccaSPeter Wemm 		if (tlen < tsp->cols)
553f0957ccaSPeter Wemm 			abort();
554f0957ccaSPeter Wemm #endif
555f0957ccaSPeter Wemm 		tlen -= tsp->cols + first;
556f0957ccaSPeter Wemm 		first = 1;
557f0957ccaSPeter Wemm 		*lp++ = tsp;
558f0957ccaSPeter Wemm 	}
559f0957ccaSPeter Wemm 	if (tlen == 0) {
560f0957ccaSPeter Wemm 		*lp = NULL;
561f0957ccaSPeter Wemm 		*jdirp = HORIZ_PRECEDE;
562f0957ccaSPeter Wemm 		return (0);
563f0957ccaSPeter Wemm 	}
564f0957ccaSPeter Wemm 
565f0957ccaSPeter Wemm 	/* Check following horizontal. */
566f0957ccaSPeter Wemm 	for (first = 0, lp = listp, tlen = sp->cols,
567f0957ccaSPeter Wemm 	    tsp = TAILQ_FIRST(gp->dq);
568f0957ccaSPeter Wemm 	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
569f0957ccaSPeter Wemm 		if (sp == tsp)
570f0957ccaSPeter Wemm 			continue;
571f0957ccaSPeter Wemm 		/* Test if precedes the screen horizontally. */
572f0957ccaSPeter Wemm 		if (tsp->roff != sp->roff + sp->rows)
573f0957ccaSPeter Wemm 			continue;
574f0957ccaSPeter Wemm 		/*
575f0957ccaSPeter Wemm 		 * Test if a subset on the horizontal axis.  If overlaps the
576f0957ccaSPeter Wemm 		 * beginning or end, we can't join on this axis at all.
577f0957ccaSPeter Wemm 		 */
578f0957ccaSPeter Wemm 		if (tsp->coff > sp->coff + sp->cols)
579f0957ccaSPeter Wemm 			continue;
580f0957ccaSPeter Wemm 		if (tsp->coff < sp->coff) {
581f0957ccaSPeter Wemm 			if (tsp->coff + tsp->cols >= sp->coff)
582f0957ccaSPeter Wemm 				break;
583f0957ccaSPeter Wemm 			continue;
584f0957ccaSPeter Wemm 		}
585f0957ccaSPeter Wemm 		if (tsp->coff + tsp->cols > sp->coff + sp->cols)
586f0957ccaSPeter Wemm 			break;
587f0957ccaSPeter Wemm #ifdef DEBUG
588f0957ccaSPeter Wemm 		if (tlen < tsp->cols)
589f0957ccaSPeter Wemm 			abort();
590f0957ccaSPeter Wemm #endif
591f0957ccaSPeter Wemm 		tlen -= tsp->cols + first;
592f0957ccaSPeter Wemm 		first = 1;
593f0957ccaSPeter Wemm 		*lp++ = tsp;
594f0957ccaSPeter Wemm 	}
595f0957ccaSPeter Wemm 	if (tlen == 0) {
596f0957ccaSPeter Wemm 		*lp = NULL;
597f0957ccaSPeter Wemm 		*jdirp = HORIZ_FOLLOW;
598f0957ccaSPeter Wemm 		return (0);
599f0957ccaSPeter Wemm 	}
600f0957ccaSPeter Wemm 	return (1);
601f0957ccaSPeter Wemm }
602f0957ccaSPeter Wemm 
603f0957ccaSPeter Wemm /*
604b8ba871bSPeter Wemm  * vs_fg --
605b8ba871bSPeter Wemm  *	Background the current screen, and foreground a new one.
606b8ba871bSPeter Wemm  *
607c271fa92SBaptiste Daroussin  * PUBLIC: int vs_fg(SCR *, SCR **, CHAR_T *, int);
608b8ba871bSPeter Wemm  */
609b8ba871bSPeter Wemm int
vs_fg(SCR * sp,SCR ** nspp,CHAR_T * name,int newscreen)610f0957ccaSPeter Wemm vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen)
611b8ba871bSPeter Wemm {
612b8ba871bSPeter Wemm 	GS *gp;
613b8ba871bSPeter Wemm 	SCR *nsp;
614f0957ccaSPeter Wemm 	char *np;
615f0957ccaSPeter Wemm 	size_t nlen;
616b8ba871bSPeter Wemm 
617b8ba871bSPeter Wemm 	gp = sp->gp;
618b8ba871bSPeter Wemm 
619f0957ccaSPeter Wemm 	if (name)
620f0957ccaSPeter Wemm 	    INT2CHAR(sp, name, STRLEN(name) + 1, np, nlen);
621f0957ccaSPeter Wemm 	else
622f0957ccaSPeter Wemm 	    np = NULL;
623b8ba871bSPeter Wemm 	if (newscreen)
624b8ba871bSPeter Wemm 		/* Get the specified background screen. */
625f0957ccaSPeter Wemm 		nsp = vs_getbg(sp, np);
626b8ba871bSPeter Wemm 	else
627b8ba871bSPeter Wemm 		/* Swap screens. */
628f0957ccaSPeter Wemm 		if (vs_swap(sp, &nsp, np))
629b8ba871bSPeter Wemm 			return (1);
630b8ba871bSPeter Wemm 
631b8ba871bSPeter Wemm 	if ((*nspp = nsp) == NULL) {
632f0957ccaSPeter Wemm 		msgq_wstr(sp, M_ERR, name,
633b8ba871bSPeter Wemm 		    name == NULL ?
634b8ba871bSPeter Wemm 		    "223|There are no background screens" :
635b8ba871bSPeter Wemm 		    "224|There's no background screen editing a file named %s");
636b8ba871bSPeter Wemm 		return (1);
637b8ba871bSPeter Wemm 	}
638b8ba871bSPeter Wemm 
639b8ba871bSPeter Wemm 	if (newscreen) {
640b8ba871bSPeter Wemm 		/* Remove the new screen from the background queue. */
641f0957ccaSPeter Wemm 		TAILQ_REMOVE(gp->hq, nsp, q);
642b8ba871bSPeter Wemm 
643b8ba871bSPeter Wemm 		/* Split the screen; if we fail, hook the screen back in. */
644b8ba871bSPeter Wemm 		if (vs_split(sp, nsp, 0)) {
645f0957ccaSPeter Wemm 			TAILQ_INSERT_TAIL(gp->hq, nsp, q);
646b8ba871bSPeter Wemm 			return (1);
647b8ba871bSPeter Wemm 		}
648b8ba871bSPeter Wemm 	} else {
649b8ba871bSPeter Wemm 		/* Move the old screen to the background queue. */
650f0957ccaSPeter Wemm 		TAILQ_REMOVE(gp->dq, sp, q);
651f0957ccaSPeter Wemm 		TAILQ_INSERT_TAIL(gp->hq, sp, q);
652b8ba871bSPeter Wemm 	}
653b8ba871bSPeter Wemm 	return (0);
654b8ba871bSPeter Wemm }
655b8ba871bSPeter Wemm 
656b8ba871bSPeter Wemm /*
657b8ba871bSPeter Wemm  * vs_bg --
658b8ba871bSPeter Wemm  *	Background the screen, and switch to the next one.
659b8ba871bSPeter Wemm  *
660c271fa92SBaptiste Daroussin  * PUBLIC: int vs_bg(SCR *);
661b8ba871bSPeter Wemm  */
662b8ba871bSPeter Wemm int
vs_bg(SCR * sp)663f0957ccaSPeter Wemm vs_bg(SCR *sp)
664b8ba871bSPeter Wemm {
665b8ba871bSPeter Wemm 	GS *gp;
666b8ba871bSPeter Wemm 	SCR *nsp;
667b8ba871bSPeter Wemm 
668b8ba871bSPeter Wemm 	gp = sp->gp;
669b8ba871bSPeter Wemm 
670b8ba871bSPeter Wemm 	/* Try and join with another screen. */
671b8ba871bSPeter Wemm 	if (vs_discard(sp, &nsp))
672b8ba871bSPeter Wemm 		return (1);
673b8ba871bSPeter Wemm 	if (nsp == NULL) {
674b8ba871bSPeter Wemm 		msgq(sp, M_ERR,
675b8ba871bSPeter Wemm 		    "225|You may not background your only displayed screen");
676b8ba871bSPeter Wemm 		return (1);
677b8ba871bSPeter Wemm 	}
678b8ba871bSPeter Wemm 
679b8ba871bSPeter Wemm 	/* Move the old screen to the background queue. */
680f0957ccaSPeter Wemm 	TAILQ_REMOVE(gp->dq, sp, q);
681f0957ccaSPeter Wemm 	TAILQ_INSERT_TAIL(gp->hq, sp, q);
682b8ba871bSPeter Wemm 
683b8ba871bSPeter Wemm 	/* Toss the screen map. */
684b8ba871bSPeter Wemm 	free(_HMAP(sp));
685b8ba871bSPeter Wemm 	_HMAP(sp) = NULL;
686b8ba871bSPeter Wemm 
687b8ba871bSPeter Wemm 	/* Switch screens. */
688b8ba871bSPeter Wemm 	sp->nextdisp = nsp;
689b8ba871bSPeter Wemm 	F_SET(sp, SC_SSWITCH);
690b8ba871bSPeter Wemm 
691b8ba871bSPeter Wemm 	return (0);
692b8ba871bSPeter Wemm }
693b8ba871bSPeter Wemm 
694b8ba871bSPeter Wemm /*
695b8ba871bSPeter Wemm  * vs_swap --
696b8ba871bSPeter Wemm  *	Swap the current screen with a backgrounded one.
697b8ba871bSPeter Wemm  *
698c271fa92SBaptiste Daroussin  * PUBLIC: int vs_swap(SCR *, SCR **, char *);
699b8ba871bSPeter Wemm  */
700b8ba871bSPeter Wemm int
vs_swap(SCR * sp,SCR ** nspp,char * name)701f0957ccaSPeter Wemm vs_swap(SCR *sp, SCR **nspp, char *name)
702b8ba871bSPeter Wemm {
703b8ba871bSPeter Wemm 	GS *gp;
704f0957ccaSPeter Wemm 	SCR *nsp, *list[2];
705b8ba871bSPeter Wemm 
706b8ba871bSPeter Wemm 	gp = sp->gp;
707b8ba871bSPeter Wemm 
708b8ba871bSPeter Wemm 	/* Get the specified background screen. */
709b8ba871bSPeter Wemm 	if ((*nspp = nsp = vs_getbg(sp, name)) == NULL)
710b8ba871bSPeter Wemm 		return (0);
711b8ba871bSPeter Wemm 
712b8ba871bSPeter Wemm 	/*
713b8ba871bSPeter Wemm 	 * Save the old screen's cursor information.
714b8ba871bSPeter Wemm 	 *
715b8ba871bSPeter Wemm 	 * XXX
716b8ba871bSPeter Wemm 	 * If called after file_end(), and the underlying file was a tmp
717b8ba871bSPeter Wemm 	 * file, it may have gone away.
718b8ba871bSPeter Wemm 	 */
719b8ba871bSPeter Wemm 	if (sp->frp != NULL) {
720b8ba871bSPeter Wemm 		sp->frp->lno = sp->lno;
721b8ba871bSPeter Wemm 		sp->frp->cno = sp->cno;
722b8ba871bSPeter Wemm 		F_SET(sp->frp, FR_CURSORSET);
723b8ba871bSPeter Wemm 	}
724b8ba871bSPeter Wemm 
725b8ba871bSPeter Wemm 	/* Switch screens. */
726b8ba871bSPeter Wemm 	sp->nextdisp = nsp;
727b8ba871bSPeter Wemm 	F_SET(sp, SC_SSWITCH);
728b8ba871bSPeter Wemm 
729b8ba871bSPeter Wemm 	/* Initialize terminal information. */
730b8ba871bSPeter Wemm 	VIP(nsp)->srows = VIP(sp)->srows;
731b8ba871bSPeter Wemm 
732b8ba871bSPeter Wemm 	/* Initialize screen information. */
733b8ba871bSPeter Wemm 	nsp->cols = sp->cols;
734b8ba871bSPeter Wemm 	nsp->rows = sp->rows;	/* XXX: Only place in vi that sets rows. */
735f0957ccaSPeter Wemm 	nsp->roff = sp->roff;
736b8ba871bSPeter Wemm 
737b8ba871bSPeter Wemm 	/*
738b8ba871bSPeter Wemm 	 * Small screens: see vs_refresh.c, section 6a.
739b8ba871bSPeter Wemm 	 *
740b8ba871bSPeter Wemm 	 * The new screens may have different screen options sizes than the
741b8ba871bSPeter Wemm 	 * old one, so use them.  Make sure that text counts aren't larger
742b8ba871bSPeter Wemm 	 * than the new screen sizes.
743b8ba871bSPeter Wemm 	 */
744b8ba871bSPeter Wemm 	if (IS_SMALL(nsp)) {
745b8ba871bSPeter Wemm 		nsp->t_minrows = nsp->t_rows = O_VAL(nsp, O_WINDOW);
746b8ba871bSPeter Wemm 		if (nsp->t_rows > sp->t_maxrows)
747b8ba871bSPeter Wemm 			nsp->t_rows = nsp->t_maxrows;
748b8ba871bSPeter Wemm 		if (nsp->t_minrows > sp->t_maxrows)
749b8ba871bSPeter Wemm 			nsp->t_minrows = nsp->t_maxrows;
750b8ba871bSPeter Wemm 	} else
751b8ba871bSPeter Wemm 		nsp->t_rows = nsp->t_maxrows = nsp->t_minrows = nsp->rows - 1;
752b8ba871bSPeter Wemm 
753b8ba871bSPeter Wemm 	/* Reset the length of the default scroll. */
754b8ba871bSPeter Wemm 	nsp->defscroll = nsp->t_maxrows / 2;
755b8ba871bSPeter Wemm 
756b8ba871bSPeter Wemm 	/* Allocate a new screen map. */
757*110d525eSBaptiste Daroussin 	CALLOC_RET(nsp, _HMAP(nsp), SIZE_HMAP(nsp), sizeof(SMAP));
758b8ba871bSPeter Wemm 	_TMAP(nsp) = _HMAP(nsp) + (nsp->t_rows - 1);
759b8ba871bSPeter Wemm 
760b8ba871bSPeter Wemm 	/* Fill the map. */
761f0957ccaSPeter Wemm 	nsp->gp = sp->gp;
762b8ba871bSPeter Wemm 	if (vs_sm_fill(nsp, nsp->lno, P_FILL))
763b8ba871bSPeter Wemm 		return (1);
764b8ba871bSPeter Wemm 
765b8ba871bSPeter Wemm 	/*
766b8ba871bSPeter Wemm 	 * The new screen replaces the old screen in the parent/child list.
767b8ba871bSPeter Wemm 	 * We insert the new screen after the old one.  If we're exiting,
768b8ba871bSPeter Wemm 	 * the exit will delete the old one, if we're foregrounding, the fg
769b8ba871bSPeter Wemm 	 * code will move the old one to the background queue.
770b8ba871bSPeter Wemm 	 */
771f0957ccaSPeter Wemm 	TAILQ_REMOVE(gp->hq, nsp, q);
772f0957ccaSPeter Wemm 	TAILQ_INSERT_AFTER(gp->dq, sp, nsp, q);
773b8ba871bSPeter Wemm 
774b8ba871bSPeter Wemm 	/*
775b8ba871bSPeter Wemm 	 * Don't change the screen's cursor information other than to
776b8ba871bSPeter Wemm 	 * note that the cursor is wrong.
777b8ba871bSPeter Wemm 	 */
778b8ba871bSPeter Wemm 	F_SET(VIP(nsp), VIP_CUR_INVALID);
779b8ba871bSPeter Wemm 
780b8ba871bSPeter Wemm 	/* Draw the new screen from scratch, and add a status line. */
781b8ba871bSPeter Wemm 	F_SET(nsp, SC_SCR_REDRAW | SC_STATUS);
782f0957ccaSPeter Wemm 
783f0957ccaSPeter Wemm 	list[0] = nsp; list[1] = NULL;
784f0957ccaSPeter Wemm 	(void)gp->scr_discard(sp, list);
785f0957ccaSPeter Wemm 
786b8ba871bSPeter Wemm 	return (0);
787b8ba871bSPeter Wemm }
788b8ba871bSPeter Wemm 
789b8ba871bSPeter Wemm /*
790b8ba871bSPeter Wemm  * vs_resize --
791b8ba871bSPeter Wemm  *	Change the absolute size of the current screen.
792b8ba871bSPeter Wemm  *
793c271fa92SBaptiste Daroussin  * PUBLIC: int vs_resize(SCR *, long, adj_t);
794b8ba871bSPeter Wemm  */
795b8ba871bSPeter Wemm int
vs_resize(SCR * sp,long int count,adj_t adj)796f0957ccaSPeter Wemm vs_resize(SCR *sp, long int count, adj_t adj)
797b8ba871bSPeter Wemm {
798b8ba871bSPeter Wemm 	GS *gp;
799f0957ccaSPeter Wemm 	SCR *g, *s, *prev, *next, *list[3] = {NULL, NULL, NULL};
800b8ba871bSPeter Wemm 	size_t g_off, s_off;
801b8ba871bSPeter Wemm 
802b8ba871bSPeter Wemm 	gp = sp->gp;
803b8ba871bSPeter Wemm 
804b8ba871bSPeter Wemm 	/*
805b8ba871bSPeter Wemm 	 * Figure out which screens will grow, which will shrink, and
806b8ba871bSPeter Wemm 	 * make sure it's possible.
807b8ba871bSPeter Wemm 	 */
808b8ba871bSPeter Wemm 	if (count == 0)
809b8ba871bSPeter Wemm 		return (0);
810b8ba871bSPeter Wemm 	if (adj == A_SET) {
811b8ba871bSPeter Wemm 		if (sp->t_maxrows == count)
812b8ba871bSPeter Wemm 			return (0);
813b8ba871bSPeter Wemm 		if (sp->t_maxrows > count) {
814b8ba871bSPeter Wemm 			adj = A_DECREASE;
815b8ba871bSPeter Wemm 			count = sp->t_maxrows - count;
816b8ba871bSPeter Wemm 		} else {
817b8ba871bSPeter Wemm 			adj = A_INCREASE;
818b8ba871bSPeter Wemm 			count = count - sp->t_maxrows;
819b8ba871bSPeter Wemm 		}
820b8ba871bSPeter Wemm 	}
821b8ba871bSPeter Wemm 
822f0957ccaSPeter Wemm 	/* Find first overlapping screen */
823f0957ccaSPeter Wemm 	for (next = TAILQ_NEXT(sp, q); next != NULL &&
824f0957ccaSPeter Wemm 	     (next->coff >= sp->coff + sp->cols ||
825f0957ccaSPeter Wemm 	      next->coff + next->cols <= sp->coff);
826f0957ccaSPeter Wemm 	     next = TAILQ_NEXT(next, q));
827f0957ccaSPeter Wemm 	/* See if we can use it */
828f0957ccaSPeter Wemm 	if (next != NULL &&
829f0957ccaSPeter Wemm 	    (sp->coff != next->coff || sp->cols != next->cols))
830f0957ccaSPeter Wemm 		next = NULL;
831f0957ccaSPeter Wemm 	for (prev = TAILQ_PREV(sp, _dqh, q); prev != NULL &&
832f0957ccaSPeter Wemm 	     (prev->coff >= sp->coff + sp->cols ||
833f0957ccaSPeter Wemm 	      prev->coff + prev->cols <= sp->coff);
834f0957ccaSPeter Wemm 	     prev = TAILQ_PREV(prev, _dqh, q));
835f0957ccaSPeter Wemm 	if (prev != NULL &&
836f0957ccaSPeter Wemm 	    (sp->coff != prev->coff || sp->cols != prev->cols))
837f0957ccaSPeter Wemm 		prev = NULL;
838f0957ccaSPeter Wemm 
839b8ba871bSPeter Wemm 	g_off = s_off = 0;
840b8ba871bSPeter Wemm 	if (adj == A_DECREASE) {
841b8ba871bSPeter Wemm 		if (count < 0)
842b8ba871bSPeter Wemm 			count = -count;
843b8ba871bSPeter Wemm 		s = sp;
844b8ba871bSPeter Wemm 		if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count)
845b8ba871bSPeter Wemm 			goto toosmall;
846f0957ccaSPeter Wemm 		if ((g = prev) == NULL) {
847f0957ccaSPeter Wemm 			if ((g = next) == NULL)
848b8ba871bSPeter Wemm 				goto toobig;
849b8ba871bSPeter Wemm 			g_off = -count;
850b8ba871bSPeter Wemm 		} else
851b8ba871bSPeter Wemm 			s_off = count;
852b8ba871bSPeter Wemm 	} else {
853b8ba871bSPeter Wemm 		g = sp;
854f0957ccaSPeter Wemm 		if ((s = next) != NULL &&
855f0957ccaSPeter Wemm 		    s->t_maxrows >= MINIMUM_SCREEN_ROWS + count)
856b8ba871bSPeter Wemm 				s_off = count;
857b8ba871bSPeter Wemm 		else
858b8ba871bSPeter Wemm 			s = NULL;
859b8ba871bSPeter Wemm 		if (s == NULL) {
860f0957ccaSPeter Wemm 			if ((s = prev) == NULL) {
861b8ba871bSPeter Wemm toobig:				msgq(sp, M_BERR, adj == A_DECREASE ?
862b8ba871bSPeter Wemm 				    "227|The screen cannot shrink" :
863b8ba871bSPeter Wemm 				    "228|The screen cannot grow");
864b8ba871bSPeter Wemm 				return (1);
865b8ba871bSPeter Wemm 			}
866b8ba871bSPeter Wemm 			if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) {
867b8ba871bSPeter Wemm toosmall:			msgq(sp, M_BERR,
868b8ba871bSPeter Wemm 				    "226|The screen can only shrink to %d rows",
869b8ba871bSPeter Wemm 				    MINIMUM_SCREEN_ROWS);
870b8ba871bSPeter Wemm 				return (1);
871b8ba871bSPeter Wemm 			}
872b8ba871bSPeter Wemm 			g_off = -count;
873b8ba871bSPeter Wemm 		}
874b8ba871bSPeter Wemm 	}
875b8ba871bSPeter Wemm 
876b8ba871bSPeter Wemm 	/*
877b8ba871bSPeter Wemm 	 * Fix up the screens; we could optimize the reformatting of the
878b8ba871bSPeter Wemm 	 * screen, but this isn't likely to be a common enough operation
879b8ba871bSPeter Wemm 	 * to make it worthwhile.
880b8ba871bSPeter Wemm 	 */
881b8ba871bSPeter Wemm 	s->rows += -count;
882f0957ccaSPeter Wemm 	s->roff += s_off;
883b8ba871bSPeter Wemm 	g->rows += count;
884f0957ccaSPeter Wemm 	g->roff += g_off;
885b8ba871bSPeter Wemm 
886b8ba871bSPeter Wemm 	g->t_rows += count;
887b8ba871bSPeter Wemm 	if (g->t_minrows == g->t_maxrows)
888b8ba871bSPeter Wemm 		g->t_minrows += count;
889b8ba871bSPeter Wemm 	g->t_maxrows += count;
890b8ba871bSPeter Wemm 	_TMAP(g) += count;
891b8ba871bSPeter Wemm 	F_SET(g, SC_SCR_REFORMAT | SC_STATUS);
892b8ba871bSPeter Wemm 
893b8ba871bSPeter Wemm 	s->t_rows -= count;
894b8ba871bSPeter Wemm 	s->t_maxrows -= count;
895b8ba871bSPeter Wemm 	if (s->t_minrows > s->t_maxrows)
896b8ba871bSPeter Wemm 		s->t_minrows = s->t_maxrows;
897b8ba871bSPeter Wemm 	_TMAP(s) -= count;
898b8ba871bSPeter Wemm 	F_SET(s, SC_SCR_REFORMAT | SC_STATUS);
899b8ba871bSPeter Wemm 
900f0957ccaSPeter Wemm 	/* XXXX */
901f0957ccaSPeter Wemm 	list[0] = g; list[1] = s;
902f0957ccaSPeter Wemm 	gp->scr_discard(0, list);
903f0957ccaSPeter Wemm 
904b8ba871bSPeter Wemm 	return (0);
905b8ba871bSPeter Wemm }
906b8ba871bSPeter Wemm 
907b8ba871bSPeter Wemm /*
908b8ba871bSPeter Wemm  * vs_getbg --
909b8ba871bSPeter Wemm  *	Get the specified background screen, or, if name is NULL, the first
910b8ba871bSPeter Wemm  *	background screen.
911b8ba871bSPeter Wemm  */
912b8ba871bSPeter Wemm static SCR *
vs_getbg(SCR * sp,char * name)913f0957ccaSPeter Wemm vs_getbg(SCR *sp, char *name)
914b8ba871bSPeter Wemm {
915b8ba871bSPeter Wemm 	GS *gp;
916b8ba871bSPeter Wemm 	SCR *nsp;
917b8ba871bSPeter Wemm 	char *p;
918b8ba871bSPeter Wemm 
919b8ba871bSPeter Wemm 	gp = sp->gp;
920b8ba871bSPeter Wemm 
921b8ba871bSPeter Wemm 	/* If name is NULL, return the first background screen on the list. */
922f0957ccaSPeter Wemm 	if (name == NULL)
923f0957ccaSPeter Wemm 		return (TAILQ_FIRST(gp->hq));
924b8ba871bSPeter Wemm 
925b8ba871bSPeter Wemm 	/* Search for a full match. */
926f0957ccaSPeter Wemm 	TAILQ_FOREACH(nsp, gp->hq, q)
927b8ba871bSPeter Wemm 		if (!strcmp(nsp->frp->name, name))
928b8ba871bSPeter Wemm 			break;
929f0957ccaSPeter Wemm 	if (nsp != NULL)
930b8ba871bSPeter Wemm 		return (nsp);
931b8ba871bSPeter Wemm 
932b8ba871bSPeter Wemm 	/* Search for a last-component match. */
933f0957ccaSPeter Wemm 	TAILQ_FOREACH(nsp, gp->hq, q) {
934b8ba871bSPeter Wemm 		if ((p = strrchr(nsp->frp->name, '/')) == NULL)
935b8ba871bSPeter Wemm 			p = nsp->frp->name;
936b8ba871bSPeter Wemm 		else
937b8ba871bSPeter Wemm 			++p;
938b8ba871bSPeter Wemm 		if (!strcmp(p, name))
939b8ba871bSPeter Wemm 			break;
940b8ba871bSPeter Wemm 	}
941f0957ccaSPeter Wemm 	if (nsp != NULL)
942b8ba871bSPeter Wemm 		return (nsp);
943b8ba871bSPeter Wemm 
944b8ba871bSPeter Wemm 	return (NULL);
945b8ba871bSPeter Wemm }
946