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.21 1993/12/02 12:15:00 bostic Exp $ (Berkeley) $Date: 1993/12/02 12:15:00 $";
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;
84 /* Link in after the parent. */
85 CIRCLEQ_INSERT_AFTER(&sp
->gp
->dq
, sp
, tsp
, q
);
87 } else { /* Parent is bottom half. */
89 tsp
->rows
= sp
->rows
- half
;
91 tsp
->t_maxrows
= tsp
->rows
- 1;
95 sp
->woff
+= tsp
->rows
;
96 sp
->t_maxrows
= sp
->rows
- 1;
98 /* Shift the parent's map down. */
100 _HMAP(sp
) + tsp
->rows
, sp
->t_maxrows
* sizeof(SMAP
));
102 /* Link in before the parent. */
103 CIRCLEQ_INSERT_BEFORE(&sp
->gp
->dq
, sp
, tsp
, q
);
108 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
110 * The child may have different screen options sizes than the
111 * parent, so use them. Make sure that the text counts aren't
112 * larger than the new screen sizes.
115 /* Fix the text line count for the parent. */
117 sp
->t_rows
-= tsp
->rows
;
119 /* Fix the parent screen. */
120 if (sp
->t_rows
> sp
->t_maxrows
)
121 sp
->t_rows
= sp
->t_maxrows
;
122 if (sp
->t_minrows
> sp
->t_maxrows
)
123 sp
->t_minrows
= sp
->t_maxrows
;
125 /* Fix the child screen. */
126 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
127 if (tsp
->t_rows
> tsp
->t_maxrows
)
128 tsp
->t_rows
= tsp
->t_maxrows
;
129 if (tsp
->t_minrows
> tsp
->t_maxrows
)
130 tsp
->t_minrows
= tsp
->t_maxrows
;
133 * If we split up, i.e. the child is on top, lines that
134 * were painted in the parent may not be painted in the
135 * child. Clear any lines not being used in the child
140 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
145 sp
->t_minrows
= sp
->t_rows
= sp
->rows
- 1;
148 * The new screen may be a small screen, even though the
149 * parent was not. Don't complain if O_WINDOW is too large,
150 * we're splitting the screen so the screen is much smaller
151 * than normal. Clear any lines not being used in the child
154 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
155 if (tsp
->t_rows
> tsp
->rows
- 1)
156 tsp
->t_minrows
= tsp
->t_rows
= tsp
->rows
- 1;
158 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
164 /* Adjust the ends of both maps. */
165 _TMAP(sp
) = _HMAP(sp
) + (sp
->t_rows
- 1);
166 _TMAP(tsp
) = _HMAP(tsp
) + (tsp
->t_rows
- 1);
169 * In any case, if the size of the scrolling region hasn't been
170 * modified by the user, reset it so it's reasonable for the split
173 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
)) {
174 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
175 O_VAL(tsp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
179 * If files specified, build the file list, else, link to the
183 for (; *argv
!= NULL
; ++argv
)
184 if (file_add(tsp
, NULL
, (*argv
)->bp
, 0) == NULL
)
187 if (file_add(tsp
, NULL
, FILENAME(sp
->frp
), 0) == NULL
)
190 if ((tsp
->frp
= file_first(tsp
, 0)) == NULL
) {
191 msgq(sp
, M_ERR
, "No files in the file list.");
196 * Copy the file state flags, start the file. Fill the child's
197 * screen map. If the file is unchanged, keep the screen and
204 tsp
->frp
->flags
= sp
->frp
->flags
;
205 tsp
->frp
->lno
= sp
->lno
;
206 tsp
->frp
->cno
= sp
->cno
;
207 F_SET(tsp
->frp
, FR_CURSORSET
);
209 /* Copy the parent's map into the child's map. */
210 memmove(_HMAP(tsp
), _HMAP(sp
), tsp
->t_rows
* sizeof(SMAP
));
212 if (file_init(tsp
, tsp
->frp
, NULL
, 0))
214 (void)svi_sm_fill(tsp
, tsp
->ep
, 1, P_TOP
);
217 /* Clear the current information lines in both screens. */
218 MOVE(sp
, INFOLINE(sp
), 0);
220 MOVE(tsp
, INFOLINE(tsp
), 0);
223 /* Redraw the status line for the parent screen. */
224 (void)status(sp
, sp
->ep
, sp
->lno
, 0);
226 /* Save the parent screen's cursor information. */
227 sp
->frp
->lno
= sp
->lno
;
228 sp
->frp
->cno
= sp
->cno
;
229 F_SET(sp
->frp
, FR_CURSORSET
);
231 /* Completely redraw the child screen. */
232 F_SET(tsp
, S_REDRAW
);
234 /* Switch screens. */
236 F_SET(sp
, S_SSWITCH
);
239 mem3
: FREE(_HMAP(tsp
), SIZE_HMAP(sp
) * sizeof(SMAP
));
240 FREE(SVP(sp
), sizeof(SVI_PRIVATE
));
241 mem2
: (void)screen_end(tsp
);
242 mem1
: FREE(tsp
, sizeof(SCR
));
248 * Background the screen, and switch to the next one.
256 /* Try and join with another screen. */
257 if ((svi_join(csp
, &sp
)))
261 "You may not background your only displayed screen.");
265 /* Switch screens. */
267 F_SET(csp
, S_SSWITCH
);
274 * Join the screen into a related screen, if one exists,
275 * and return that screen.
285 * If a split screen, add space to parent/child. Make no effort
286 * to clean up the screen's values. If it's not exiting, we'll
287 * get it when the user asks to show it again.
289 if ((sp
= csp
->q
.cqe_prev
) == (void *)&csp
->gp
->dq
) {
290 if ((sp
= csp
->q
.cqe_next
) == (void *)&csp
->gp
->dq
) {
294 sp
->woff
= csp
->woff
;
296 sp
->rows
+= csp
->rows
;
297 if (ISSMALLSCREEN(sp
)) {
298 sp
->t_maxrows
+= csp
->rows
;
299 for (cnt
= sp
->t_rows
; ++cnt
<= sp
->t_maxrows
;) {
303 TMAP
= HMAP
+ (sp
->t_rows
- 1);
305 sp
->t_maxrows
+= csp
->rows
;
306 sp
->t_rows
= sp
->t_minrows
= sp
->t_maxrows
;
307 TMAP
= HMAP
+ (sp
->t_rows
- 1);
308 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
314 * If the size of the scrolling region hasn't been modified by
315 * the user, reset it so it's reasonable for the new screen.
317 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
318 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
320 /* Screen is no longer displayed. */
321 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
322 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
330 * Background the current screen, and foreground a new one.
339 if (svi_swap(csp
, &sp
, name
))
343 msgq(csp
, M_ERR
, "There are no background screens.");
346 "There's no background screen editing a file named %s.",
355 * Swap the current screen with a hidden one.
358 svi_swap(csp
, nsp
, name
)
365 /* Find the screen, or, if name is NULL, the first screen. */
366 for (sp
= csp
->gp
->hq
.cqh_first
;
367 sp
!= (void *)&csp
->gp
->hq
; sp
= sp
->q
.cqe_next
)
368 if (name
== NULL
|| !strcmp(FILENAME(sp
->frp
), name
))
370 if (sp
== (void *)&csp
->gp
->hq
) {
376 /* Save the old screen's cursor information. */
377 csp
->frp
->lno
= csp
->lno
;
378 csp
->frp
->cno
= csp
->cno
;
379 F_SET(csp
->frp
, FR_CURSORSET
);
381 /* Switch screens. */
383 F_SET(csp
, S_SSWITCH
);
385 /* Initialize terminal information. */
386 SVP(sp
)->srows
= SVP(csp
)->srows
;
388 issmallscreen
= ISSMALLSCREEN(sp
);
390 /* Initialize screen information. */
391 sp
->rows
= csp
->rows
;
392 sp
->cols
= csp
->cols
;
393 sp
->woff
= csp
->woff
;
396 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
398 * The new screens may have different screen options sizes than the
399 * old one, so use them. Make sure that text counts aren't larger
400 * than the new screen sizes.
403 sp
->t_minrows
= sp
->t_rows
= O_VAL(sp
, O_WINDOW
);
404 if (sp
->t_rows
> csp
->t_maxrows
)
405 sp
->t_rows
= sp
->t_maxrows
;
406 if (sp
->t_minrows
> csp
->t_maxrows
)
407 sp
->t_minrows
= sp
->t_maxrows
;
409 sp
->t_rows
= sp
->t_maxrows
= sp
->rows
- 1;
412 * If the size of the scrolling region hasn't been modified by
413 * the user, reset it so it's reasonable for the new screen.
415 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
416 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
419 * Don't change the screen's cursor information other than to
420 * note that the cursor is wrong.
422 F_SET(SVP(sp
), SVI_CUR_INVALID
);
425 * The HMAP may be NULL, if the screen got resized and
426 * a bunch of screens had to be hidden.
429 (HMAP
= malloc(SIZE_HMAP(sp
) * sizeof(SMAP
))) == NULL
) {
430 msgq(sp
, M_SYSERR
, NULL
);
433 TMAP
= HMAP
+ (sp
->t_rows
- 1);
436 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
439 /* The new screen replaces the old screen in the parent/child list. */
440 CIRCLEQ_REMOVE(&sp
->gp
->hq
, sp
, q
);
441 CIRCLEQ_INSERT_AFTER(&csp
->gp
->dq
, csp
, sp
, q
);
442 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
443 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
451 * Change the size of the current screen.
454 svi_resize(sp
, count
)
461 * Figure out which screens will grow, which will shrink, and
462 * make sure it's possible.
469 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
471 if ((g
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
472 if ((g
= sp
->q
.cqe_next
) == (void *)&sp
->gp
->dq
)
479 if ((s
= sp
->q
.cqe_next
) != (void *)&sp
->gp
->dq
)
480 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
487 if ((s
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
488 toobig
: msgq(sp
, M_BERR
, "The screen cannot %s.",
489 count
< 0 ? "shrink" : "grow");
492 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
) {
493 toosmall
: msgq(sp
, M_BERR
,
494 "The screen can only shrink to %d rows.",
495 MINIMUM_SCREEN_ROWS
);
502 /* Update the screens. */
505 if (g
->t_minrows
== g
->t_maxrows
)
506 g
->t_minrows
+= count
;
507 g
->t_maxrows
+= count
;
508 _TMAP(g
) = _HMAP(g
) + (g
->t_rows
- 1);
509 (void)status(g
, g
->ep
, g
->lno
, 0);
514 s
->t_maxrows
-= count
;
515 if (s
->t_minrows
> s
->t_maxrows
)
516 s
->t_minrows
= s
->t_maxrows
;
517 _TMAP(s
) = _HMAP(s
) + (s
->t_rows
- 1);
518 (void)status(s
, s
->ep
, s
->lno
, 0);