3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
9 static char sccsid
[] = "$Id: vs_split.c,v 8.26 1993/12/10 12:22:10 bostic Exp $ (Berkeley) $Date: 1993/12/10 12:22:10 $";
12 #include <sys/types.h>
20 #include "svi_screen.h"
34 int issmallscreen
, splitup
;
36 /* Check to see if it's possible. */
38 if (half
< MINIMUM_SCREEN_ROWS
) {
39 msgq(sp
, M_ERR
, "Screen must be larger than %d to split",
44 /* Get a new screen. */
45 if (screen_init(sp
, &tsp
, 0))
47 MALLOC(sp
, _HMAP(tsp
), SMAP
*, SIZE_HMAP(sp
) * sizeof(SMAP
));
48 if (_HMAP(tsp
) == NULL
)
51 /* INITIALIZED AT SCREEN CREATE. */
53 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
55 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
56 * Set a flag so we know to fix the screen up later.
58 issmallscreen
= ISSMALLSCREEN(sp
);
61 * Split the screen, and link the screens together. If the cursor
62 * is in the top half of the current screen, the new screen goes
63 * under the current screen. Else, it goes above the current screen.
65 * The columns in the screen don't change.
69 cnt
= svi_sm_cursor(sp
, sp
->ep
, &smp
) ? 0 : smp
- HMAP
;
70 if (cnt
<= half
) { /* Parent is top half. */
72 tsp
->rows
= sp
->rows
- half
;
73 tsp
->woff
= sp
->woff
+ half
;
74 tsp
->t_maxrows
= tsp
->rows
- 1;
78 sp
->t_maxrows
= sp
->rows
- 1;
81 } else { /* Parent is bottom half. */
83 tsp
->rows
= sp
->rows
- half
;
85 tsp
->t_maxrows
= tsp
->rows
- 1;
89 sp
->woff
+= tsp
->rows
;
90 sp
->t_maxrows
= sp
->rows
- 1;
92 /* Shift the parent's map down. */
94 _HMAP(sp
) + tsp
->rows
, sp
->t_maxrows
* sizeof(SMAP
));
100 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
102 * The child may have different screen options sizes than the
103 * parent, so use them. Make sure that the text counts aren't
104 * larger than the new screen sizes.
107 /* Fix the text line count for the parent. */
109 sp
->t_rows
-= tsp
->rows
;
111 /* Fix the parent screen. */
112 if (sp
->t_rows
> sp
->t_maxrows
)
113 sp
->t_rows
= sp
->t_maxrows
;
114 if (sp
->t_minrows
> sp
->t_maxrows
)
115 sp
->t_minrows
= sp
->t_maxrows
;
117 /* Fix the child screen. */
118 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
119 if (tsp
->t_rows
> tsp
->t_maxrows
)
120 tsp
->t_rows
= tsp
->t_maxrows
;
121 if (tsp
->t_minrows
> tsp
->t_maxrows
)
122 tsp
->t_minrows
= tsp
->t_maxrows
;
125 * If we split up, i.e. the child is on top, lines that
126 * were painted in the parent may not be painted in the
127 * child. Clear any lines not being used in the child
132 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
137 sp
->t_minrows
= sp
->t_rows
= sp
->rows
- 1;
140 * The new screen may be a small screen, even though the
141 * parent was not. Don't complain if O_WINDOW is too large,
142 * we're splitting the screen so the screen is much smaller
143 * than normal. Clear any lines not being used in the child
146 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
147 if (tsp
->t_rows
> tsp
->rows
- 1)
148 tsp
->t_minrows
= tsp
->t_rows
= tsp
->rows
- 1;
150 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
156 /* Adjust the ends of both maps. */
157 _TMAP(sp
) = _HMAP(sp
) + (sp
->t_rows
- 1);
158 _TMAP(tsp
) = _HMAP(tsp
) + (tsp
->t_rows
- 1);
161 * In any case, if the size of the scrolling region hasn't been
162 * modified by the user, reset it so it's reasonable for the split
165 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
)) {
166 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
167 O_VAL(tsp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
171 * If files specified, build the file list, else, link to the
175 if (file_add(tsp
, NULL
, FILENAME(sp
->frp
), 0) == NULL
)
178 for (; (*argv
)->len
!= 0; ++argv
)
179 if (file_add(tsp
, NULL
, (*argv
)->bp
, 0) == NULL
)
182 /* Set up the argument and current FREF pointers. */
183 if ((tsp
->frp
= file_first(tsp
)) == NULL
) {
184 msgq(sp
, M_ERR
, "No files in the file list.");
187 tsp
->a_frp
= tsp
->frp
;
190 * Copy the file state flags, start the file. Fill the child's
191 * screen map. If the file is unchanged, keep the screen and
198 tsp
->frp
->flags
= sp
->frp
->flags
;
199 tsp
->frp
->lno
= sp
->lno
;
200 tsp
->frp
->cno
= sp
->cno
;
201 F_SET(tsp
->frp
, FR_CURSORSET
);
203 /* Copy the parent's map into the child's map. */
204 memmove(_HMAP(tsp
), _HMAP(sp
), tsp
->t_rows
* sizeof(SMAP
));
206 if (file_init(tsp
, tsp
->frp
, NULL
, 0))
208 (void)svi_sm_fill(tsp
, tsp
->ep
, 1, P_TOP
);
211 /* Everything's initialized, put the screen on the displayed queue.*/
213 /* Link in before the parent. */
214 CIRCLEQ_INSERT_BEFORE(&sp
->gp
->dq
, sp
, tsp
, q
);
216 /* Link in after the parent. */
217 CIRCLEQ_INSERT_AFTER(&sp
->gp
->dq
, sp
, tsp
, q
);
220 /* Clear the current information lines in both screens. */
221 MOVE(sp
, INFOLINE(sp
), 0);
223 MOVE(tsp
, INFOLINE(tsp
), 0);
226 /* Redraw the status line for the parent screen. */
227 (void)status(sp
, sp
->ep
, sp
->lno
, 0);
229 /* Save the parent screen's cursor information. */
230 sp
->frp
->lno
= sp
->lno
;
231 sp
->frp
->cno
= sp
->cno
;
232 F_SET(sp
->frp
, FR_CURSORSET
);
234 /* Completely redraw the child screen. */
235 F_SET(tsp
, S_REDRAW
);
237 /* Switch screens. */
239 F_SET(sp
, S_SSWITCH
);
242 mem3
: FREE(_HMAP(tsp
), SIZE_HMAP(sp
) * sizeof(SMAP
));
243 FREE(SVP(sp
), sizeof(SVI_PRIVATE
));
244 mem2
: (void)screen_end(tsp
);
245 mem1
: FREE(tsp
, sizeof(SCR
));
251 * Background the screen, and switch to the next one.
259 /* Try and join with another screen. */
260 if ((svi_join(csp
, &sp
)))
264 "You may not background your only displayed screen.");
268 /* Move the old screen to the hidden queue. */
269 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
270 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
272 /* Switch screens. */
274 F_SET(csp
, S_SSWITCH
);
281 * Join the screen into a related screen, if one exists,
282 * and return that screen.
292 * If a split screen, add space to parent/child. Make no effort
293 * to clean up the screen's values. If it's not exiting, we'll
294 * get it when the user asks to show it again.
296 if ((sp
= csp
->q
.cqe_prev
) == (void *)&csp
->gp
->dq
) {
297 if ((sp
= csp
->q
.cqe_next
) == (void *)&csp
->gp
->dq
) {
301 sp
->woff
= csp
->woff
;
303 sp
->rows
+= csp
->rows
;
304 if (ISSMALLSCREEN(sp
)) {
305 sp
->t_maxrows
+= csp
->rows
;
306 for (cnt
= sp
->t_rows
; ++cnt
<= sp
->t_maxrows
;) {
310 TMAP
= HMAP
+ (sp
->t_rows
- 1);
312 sp
->t_maxrows
+= csp
->rows
;
313 sp
->t_rows
= sp
->t_minrows
= sp
->t_maxrows
;
314 TMAP
= HMAP
+ (sp
->t_rows
- 1);
315 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
321 * If the size of the scrolling region hasn't been modified by
322 * the user, reset it so it's reasonable for the new screen.
324 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
325 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
333 * Background the current screen, and foreground a new one.
342 if (svi_swap(csp
, &sp
, name
))
346 msgq(csp
, M_ERR
, "There are no background screens.");
349 "There's no background screen editing a file named %s.",
354 /* Move the old screen to the hidden queue. */
355 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
356 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
363 * Swap the current screen with a hidden one.
366 svi_swap(csp
, nsp
, name
)
373 /* Find the screen, or, if name is NULL, the first screen. */
374 for (sp
= csp
->gp
->hq
.cqh_first
;
375 sp
!= (void *)&csp
->gp
->hq
; sp
= sp
->q
.cqe_next
)
376 if (name
== NULL
|| !strcmp(FILENAME(sp
->frp
), name
))
378 if (sp
== (void *)&csp
->gp
->hq
) {
384 /* Save the old screen's cursor information. */
385 csp
->frp
->lno
= csp
->lno
;
386 csp
->frp
->cno
= csp
->cno
;
387 F_SET(csp
->frp
, FR_CURSORSET
);
389 /* Switch screens. */
391 F_SET(csp
, S_SSWITCH
);
393 /* Initialize terminal information. */
394 SVP(sp
)->srows
= SVP(csp
)->srows
;
396 issmallscreen
= ISSMALLSCREEN(sp
);
398 /* Initialize screen information. */
399 sp
->rows
= csp
->rows
;
400 sp
->cols
= csp
->cols
;
401 sp
->woff
= csp
->woff
;
404 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
406 * The new screens may have different screen options sizes than the
407 * old one, so use them. Make sure that text counts aren't larger
408 * than the new screen sizes.
411 sp
->t_minrows
= sp
->t_rows
= O_VAL(sp
, O_WINDOW
);
412 if (sp
->t_rows
> csp
->t_maxrows
)
413 sp
->t_rows
= sp
->t_maxrows
;
414 if (sp
->t_minrows
> csp
->t_maxrows
)
415 sp
->t_minrows
= sp
->t_maxrows
;
417 sp
->t_rows
= sp
->t_maxrows
= sp
->rows
- 1;
420 * If the size of the scrolling region hasn't been modified by
421 * the user, reset it so it's reasonable for the new screen.
423 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
424 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
427 * Don't change the screen's cursor information other than to
428 * note that the cursor is wrong.
430 F_SET(SVP(sp
), SVI_CUR_INVALID
);
433 * The HMAP may be NULL, if the screen got resized and
434 * a bunch of screens had to be hidden.
437 MALLOC_RET(sp
, HMAP
, SMAP
*, SIZE_HMAP(sp
) * sizeof(SMAP
));
438 TMAP
= HMAP
+ (sp
->t_rows
- 1);
441 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
445 * The new screen replaces the old screen in the parent/child list.
446 * We insert the new screen after the old one. If we're exiting,
447 * the exit will delete the old one, if we're foregrounding, the fg
448 * code will move the old one to the hidden queue.
450 CIRCLEQ_REMOVE(&sp
->gp
->hq
, sp
, q
);
451 CIRCLEQ_INSERT_AFTER(&csp
->gp
->dq
, csp
, sp
, q
);
459 * Change the absolute size of the current screen.
469 * Figure out which screens will grow, which will shrink, and
470 * make sure it's possible.
477 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
479 if ((g
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
480 if ((g
= sp
->q
.cqe_next
) == (void *)&sp
->gp
->dq
)
487 if ((s
= sp
->q
.cqe_next
) != (void *)&sp
->gp
->dq
)
488 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
495 if ((s
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
496 toobig
: msgq(sp
, M_BERR
, "The screen cannot %s.",
497 count
< 0 ? "shrink" : "grow");
500 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
) {
501 toosmall
: msgq(sp
, M_BERR
,
502 "The screen can only shrink to %d rows.",
503 MINIMUM_SCREEN_ROWS
);
510 /* Update the screens. */
513 if (g
->t_minrows
== g
->t_maxrows
)
514 g
->t_minrows
+= count
;
515 g
->t_maxrows
+= count
;
516 _TMAP(g
) = _HMAP(g
) + (g
->t_rows
- 1);
517 (void)status(g
, g
->ep
, g
->lno
, 0);
522 s
->t_maxrows
-= count
;
523 if (s
->t_minrows
> s
->t_maxrows
)
524 s
->t_minrows
= s
->t_maxrows
;
525 _TMAP(s
) = _HMAP(s
) + (s
->t_rows
- 1);
526 (void)status(s
, s
->ep
, s
->lno
, 0);