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.23 1993/12/02 15:14:42 bostic Exp $ (Berkeley) $Date: 1993/12/02 15:14:42 $";
12 #include <sys/types.h>
20 #include "svi_screen.h"
34 int issmallscreen
, nochange
, 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 if ((_HMAP(tsp
) = malloc(SIZE_HMAP(sp
) * sizeof(SMAP
))) == NULL
) {
48 msgq(sp
, M_SYSERR
, NULL
);
52 /* INITIALIZED AT SCREEN CREATE. */
54 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
56 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
57 * Set a flag so we know to fix the screen up later.
59 issmallscreen
= ISSMALLSCREEN(sp
);
61 /* Flag if we're changing screens. */
62 nochange
= argv
== NULL
;
65 * Split the screen, and link the screens together. If the cursor
66 * is in the top half of the current screen, the new screen goes
67 * under the current screen. Else, it goes above the current screen.
69 * The columns in the screen don't change.
73 cnt
= svi_sm_cursor(sp
, sp
->ep
, &smp
) ? 0 : smp
- HMAP
;
74 if (cnt
<= half
) { /* Parent is top half. */
76 tsp
->rows
= sp
->rows
- half
;
77 tsp
->woff
= sp
->woff
+ half
;
78 tsp
->t_maxrows
= tsp
->rows
- 1;
82 sp
->t_maxrows
= sp
->rows
- 1;
85 } else { /* Parent is bottom half. */
87 tsp
->rows
= sp
->rows
- half
;
89 tsp
->t_maxrows
= tsp
->rows
- 1;
93 sp
->woff
+= tsp
->rows
;
94 sp
->t_maxrows
= sp
->rows
- 1;
96 /* Shift the parent's map down. */
98 _HMAP(sp
) + tsp
->rows
, sp
->t_maxrows
* sizeof(SMAP
));
104 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
106 * The child may have different screen options sizes than the
107 * parent, so use them. Make sure that the text counts aren't
108 * larger than the new screen sizes.
111 /* Fix the text line count for the parent. */
113 sp
->t_rows
-= tsp
->rows
;
115 /* Fix the parent screen. */
116 if (sp
->t_rows
> sp
->t_maxrows
)
117 sp
->t_rows
= sp
->t_maxrows
;
118 if (sp
->t_minrows
> sp
->t_maxrows
)
119 sp
->t_minrows
= sp
->t_maxrows
;
121 /* Fix the child screen. */
122 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
123 if (tsp
->t_rows
> tsp
->t_maxrows
)
124 tsp
->t_rows
= tsp
->t_maxrows
;
125 if (tsp
->t_minrows
> tsp
->t_maxrows
)
126 tsp
->t_minrows
= tsp
->t_maxrows
;
129 * If we split up, i.e. the child is on top, lines that
130 * were painted in the parent may not be painted in the
131 * child. Clear any lines not being used in the child
136 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
141 sp
->t_minrows
= sp
->t_rows
= sp
->rows
- 1;
144 * The new screen may be a small screen, even though the
145 * parent was not. Don't complain if O_WINDOW is too large,
146 * we're splitting the screen so the screen is much smaller
147 * than normal. Clear any lines not being used in the child
150 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
151 if (tsp
->t_rows
> tsp
->rows
- 1)
152 tsp
->t_minrows
= tsp
->t_rows
= tsp
->rows
- 1;
154 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
160 /* Adjust the ends of both maps. */
161 _TMAP(sp
) = _HMAP(sp
) + (sp
->t_rows
- 1);
162 _TMAP(tsp
) = _HMAP(tsp
) + (tsp
->t_rows
- 1);
165 * In any case, if the size of the scrolling region hasn't been
166 * modified by the user, reset it so it's reasonable for the split
169 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
)) {
170 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
171 O_VAL(tsp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
175 * If files specified, build the file list, else, link to the
179 for (; *argv
!= NULL
; ++argv
)
180 if (file_add(tsp
, NULL
, (*argv
)->bp
, 0) == NULL
)
183 if (file_add(tsp
, NULL
, FILENAME(sp
->frp
), 0) == NULL
)
186 if ((tsp
->frp
= file_first(tsp
, 0)) == NULL
) {
187 msgq(sp
, M_ERR
, "No files in the file list.");
192 * Copy the file state flags, start the file. Fill the child's
193 * screen map. If the file is unchanged, keep the screen and
200 tsp
->frp
->flags
= sp
->frp
->flags
;
201 tsp
->frp
->lno
= sp
->lno
;
202 tsp
->frp
->cno
= sp
->cno
;
203 F_SET(tsp
->frp
, FR_CURSORSET
);
205 /* Copy the parent's map into the child's map. */
206 memmove(_HMAP(tsp
), _HMAP(sp
), tsp
->t_rows
* sizeof(SMAP
));
208 if (file_init(tsp
, tsp
->frp
, NULL
, 0))
210 (void)svi_sm_fill(tsp
, tsp
->ep
, 1, P_TOP
);
213 /* Everything's initialized, put the screen on the displayed queue.*/
215 /* Link in before the parent. */
216 CIRCLEQ_INSERT_BEFORE(&sp
->gp
->dq
, sp
, tsp
, q
);
218 /* Link in after the parent. */
219 CIRCLEQ_INSERT_AFTER(&sp
->gp
->dq
, sp
, tsp
, q
);
222 /* Clear the current information lines in both screens. */
223 MOVE(sp
, INFOLINE(sp
), 0);
225 MOVE(tsp
, INFOLINE(tsp
), 0);
228 /* Redraw the status line for the parent screen. */
229 (void)status(sp
, sp
->ep
, sp
->lno
, 0);
231 /* Save the parent screen's cursor information. */
232 sp
->frp
->lno
= sp
->lno
;
233 sp
->frp
->cno
= sp
->cno
;
234 F_SET(sp
->frp
, FR_CURSORSET
);
236 /* Completely redraw the child screen. */
237 F_SET(tsp
, S_REDRAW
);
239 /* Switch screens. */
241 F_SET(sp
, S_SSWITCH
);
244 mem3
: FREE(_HMAP(tsp
), SIZE_HMAP(sp
) * sizeof(SMAP
));
245 FREE(SVP(sp
), sizeof(SVI_PRIVATE
));
246 mem2
: (void)screen_end(tsp
);
247 mem1
: FREE(tsp
, sizeof(SCR
));
253 * Background the screen, and switch to the next one.
261 /* Try and join with another screen. */
262 if ((svi_join(csp
, &sp
)))
266 "You may not background your only displayed screen.");
270 /* Move the old screen to the hidden queue. */
271 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
272 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
274 /* Switch screens. */
276 F_SET(csp
, S_SSWITCH
);
283 * Join the screen into a related screen, if one exists,
284 * and return that screen.
294 * If a split screen, add space to parent/child. Make no effort
295 * to clean up the screen's values. If it's not exiting, we'll
296 * get it when the user asks to show it again.
298 if ((sp
= csp
->q
.cqe_prev
) == (void *)&csp
->gp
->dq
) {
299 if ((sp
= csp
->q
.cqe_next
) == (void *)&csp
->gp
->dq
) {
303 sp
->woff
= csp
->woff
;
305 sp
->rows
+= csp
->rows
;
306 if (ISSMALLSCREEN(sp
)) {
307 sp
->t_maxrows
+= csp
->rows
;
308 for (cnt
= sp
->t_rows
; ++cnt
<= sp
->t_maxrows
;) {
312 TMAP
= HMAP
+ (sp
->t_rows
- 1);
314 sp
->t_maxrows
+= csp
->rows
;
315 sp
->t_rows
= sp
->t_minrows
= sp
->t_maxrows
;
316 TMAP
= HMAP
+ (sp
->t_rows
- 1);
317 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
323 * If the size of the scrolling region hasn't been modified by
324 * the user, reset it so it's reasonable for the new screen.
326 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
327 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
335 * Background the current screen, and foreground a new one.
344 if (svi_swap(csp
, &sp
, name
))
348 msgq(csp
, M_ERR
, "There are no background screens.");
351 "There's no background screen editing a file named %s.",
356 /* Move the old screen to the hidden queue. */
357 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
358 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
365 * Swap the current screen with a hidden one.
368 svi_swap(csp
, nsp
, name
)
375 /* Find the screen, or, if name is NULL, the first screen. */
376 for (sp
= csp
->gp
->hq
.cqh_first
;
377 sp
!= (void *)&csp
->gp
->hq
; sp
= sp
->q
.cqe_next
)
378 if (name
== NULL
|| !strcmp(FILENAME(sp
->frp
), name
))
380 if (sp
== (void *)&csp
->gp
->hq
) {
386 /* Save the old screen's cursor information. */
387 csp
->frp
->lno
= csp
->lno
;
388 csp
->frp
->cno
= csp
->cno
;
389 F_SET(csp
->frp
, FR_CURSORSET
);
391 /* Switch screens. */
393 F_SET(csp
, S_SSWITCH
);
395 /* Initialize terminal information. */
396 SVP(sp
)->srows
= SVP(csp
)->srows
;
398 issmallscreen
= ISSMALLSCREEN(sp
);
400 /* Initialize screen information. */
401 sp
->rows
= csp
->rows
;
402 sp
->cols
= csp
->cols
;
403 sp
->woff
= csp
->woff
;
406 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
408 * The new screens may have different screen options sizes than the
409 * old one, so use them. Make sure that text counts aren't larger
410 * than the new screen sizes.
413 sp
->t_minrows
= sp
->t_rows
= O_VAL(sp
, O_WINDOW
);
414 if (sp
->t_rows
> csp
->t_maxrows
)
415 sp
->t_rows
= sp
->t_maxrows
;
416 if (sp
->t_minrows
> csp
->t_maxrows
)
417 sp
->t_minrows
= sp
->t_maxrows
;
419 sp
->t_rows
= sp
->t_maxrows
= sp
->rows
- 1;
422 * If the size of the scrolling region hasn't been modified by
423 * the user, reset it so it's reasonable for the new screen.
425 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
426 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
429 * Don't change the screen's cursor information other than to
430 * note that the cursor is wrong.
432 F_SET(SVP(sp
), SVI_CUR_INVALID
);
435 * The HMAP may be NULL, if the screen got resized and
436 * a bunch of screens had to be hidden.
439 (HMAP
= malloc(SIZE_HMAP(sp
) * sizeof(SMAP
))) == NULL
) {
440 msgq(sp
, M_SYSERR
, NULL
);
443 TMAP
= HMAP
+ (sp
->t_rows
- 1);
446 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
450 * The new screen replaces the old screen in the parent/child list.
451 * We insert the new screen after the old one. If we're exiting,
452 * the exit will delete the old one, if we're foregrounding, the fg
453 * code will move the old one to the hidden queue.
455 CIRCLEQ_REMOVE(&sp
->gp
->hq
, sp
, q
);
456 CIRCLEQ_INSERT_AFTER(&csp
->gp
->dq
, csp
, sp
, q
);
464 * Change the absolute size of the current screen.
474 * Figure out which screens will grow, which will shrink, and
475 * make sure it's possible.
482 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
484 if ((g
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
485 if ((g
= sp
->q
.cqe_next
) == (void *)&sp
->gp
->dq
)
492 if ((s
= sp
->q
.cqe_next
) != (void *)&sp
->gp
->dq
)
493 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
500 if ((s
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
501 toobig
: msgq(sp
, M_BERR
, "The screen cannot %s.",
502 count
< 0 ? "shrink" : "grow");
505 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
) {
506 toosmall
: msgq(sp
, M_BERR
,
507 "The screen can only shrink to %d rows.",
508 MINIMUM_SCREEN_ROWS
);
515 /* Update the screens. */
518 if (g
->t_minrows
== g
->t_maxrows
)
519 g
->t_minrows
+= count
;
520 g
->t_maxrows
+= count
;
521 _TMAP(g
) = _HMAP(g
) + (g
->t_rows
- 1);
522 (void)status(g
, g
->ep
, g
->lno
, 0);
527 s
->t_maxrows
-= count
;
528 if (s
->t_minrows
> s
->t_maxrows
)
529 s
->t_minrows
= s
->t_maxrows
;
530 _TMAP(s
) = _HMAP(s
) + (s
->t_rows
- 1);
531 (void)status(s
, s
->ep
, s
->lno
, 0);