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