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.29 1993/12/22 15:12:14 bostic Exp $ (Berkeley) $Date: 1993/12/22 15:12:14 $";
12 #include <sys/types.h>
20 #include "svi_screen.h"
33 SVI_PRIVATE saved_svp
;
36 int issmallscreen
, splitup
;
38 /* Check to see if it's possible. */
40 if (half
< MINIMUM_SCREEN_ROWS
) {
41 msgq(sp
, M_ERR
, "Screen must be larger than %d to split",
46 /* Get a new screen. */
47 if (screen_init(sp
, &tsp
, 0))
49 MALLOC(sp
, _HMAP(tsp
), SMAP
*, SIZE_HMAP(sp
) * sizeof(SMAP
));
50 if (_HMAP(tsp
) == NULL
)
54 * We're about to modify the current screen. Save the contents
55 * in case something goes horribly, senselessly wrong.
60 /* INITIALIZED AT SCREEN CREATE. */
62 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
64 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
65 * Set a flag so we know to fix the screen up later.
67 issmallscreen
= ISSMALLSCREEN(sp
);
70 * Split the screen, and link the screens together. If the cursor
71 * is in the top half of the current screen, the new screen goes
72 * under the current screen. Else, it goes above the current screen.
74 * The columns in the screen don't change.
78 cnt
= svi_sm_cursor(sp
, sp
->ep
, &smp
) ? 0 : smp
- HMAP
;
79 if (cnt
<= half
) { /* Parent is top half. */
81 tsp
->rows
= sp
->rows
- half
;
82 tsp
->woff
= sp
->woff
+ half
;
83 tsp
->t_maxrows
= tsp
->rows
- 1;
87 sp
->t_maxrows
= sp
->rows
- 1;
90 } else { /* Parent is bottom half. */
92 tsp
->rows
= sp
->rows
- half
;
94 tsp
->t_maxrows
= tsp
->rows
- 1;
98 sp
->woff
+= tsp
->rows
;
99 sp
->t_maxrows
= sp
->rows
- 1;
101 /* Shift the parent's map down. */
103 _HMAP(sp
) + tsp
->rows
, sp
->t_maxrows
* sizeof(SMAP
));
109 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
111 * The child may have different screen options sizes than the
112 * parent, so use them. Make sure that the text counts aren't
113 * larger than the new screen sizes.
116 /* Fix the text line count for the parent. */
118 sp
->t_rows
-= tsp
->rows
;
120 /* Fix the parent screen. */
121 if (sp
->t_rows
> sp
->t_maxrows
)
122 sp
->t_rows
= sp
->t_maxrows
;
123 if (sp
->t_minrows
> sp
->t_maxrows
)
124 sp
->t_minrows
= sp
->t_maxrows
;
126 /* Fix the child screen. */
127 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
128 if (tsp
->t_rows
> tsp
->t_maxrows
)
129 tsp
->t_rows
= tsp
->t_maxrows
;
130 if (tsp
->t_minrows
> tsp
->t_maxrows
)
131 tsp
->t_minrows
= tsp
->t_maxrows
;
134 * If we split up, i.e. the child is on top, lines that
135 * were painted in the parent may not be painted in the
136 * child. Clear any lines not being used in the child
141 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
146 sp
->t_minrows
= sp
->t_rows
= sp
->rows
- 1;
149 * The new screen may be a small screen, even though the
150 * parent was not. Don't complain if O_WINDOW is too large,
151 * we're splitting the screen so the screen is much smaller
152 * than normal. Clear any lines not being used in the child
155 tsp
->t_minrows
= tsp
->t_rows
= O_VAL(sp
, O_WINDOW
);
156 if (tsp
->t_rows
> tsp
->rows
- 1)
157 tsp
->t_minrows
= tsp
->t_rows
= tsp
->rows
- 1;
159 for (cnt
= tsp
->t_rows
; ++cnt
<= tsp
->t_maxrows
;) {
165 /* Adjust the ends of both maps. */
166 _TMAP(sp
) = _HMAP(sp
) + (sp
->t_rows
- 1);
167 _TMAP(tsp
) = _HMAP(tsp
) + (tsp
->t_rows
- 1);
170 * In any case, if the size of the scrolling region hasn't been
171 * modified by the user, reset it so it's reasonable for the split
174 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
)) {
175 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
176 O_VAL(tsp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
180 * If files specified, build the file list, else, link to the
184 if (file_add(tsp
, NULL
, FILENAME(sp
->frp
), 0) == NULL
)
187 for (; (*argv
)->len
!= 0; ++argv
)
188 if (file_add(tsp
, NULL
, (*argv
)->bp
, 0) == NULL
)
191 /* Set up the argument and current FREF pointers. */
192 if ((tsp
->frp
= file_first(tsp
)) == NULL
) {
193 msgq(sp
, M_ERR
, "No files in the file list.");
197 tsp
->a_frp
= tsp
->frp
;
200 * Copy the file state flags, start the file. Fill the child's
201 * screen map. If the file is unchanged, keep the screen and
208 tsp
->frp
->flags
= sp
->frp
->flags
;
209 tsp
->frp
->lno
= sp
->lno
;
210 tsp
->frp
->cno
= sp
->cno
;
211 F_SET(tsp
->frp
, FR_CURSORSET
);
213 /* Copy the parent's map into the child's map. */
214 memmove(_HMAP(tsp
), _HMAP(sp
), tsp
->t_rows
* sizeof(SMAP
));
216 if (file_init(tsp
, tsp
->frp
, NULL
, 0))
218 (void)svi_sm_fill(tsp
, tsp
->ep
, 1, P_TOP
);
221 /* Everything's initialized, put the screen on the displayed queue.*/
223 /* Link in before the parent. */
224 CIRCLEQ_INSERT_BEFORE(&sp
->gp
->dq
, sp
, tsp
, q
);
226 /* Link in after the parent. */
227 CIRCLEQ_INSERT_AFTER(&sp
->gp
->dq
, sp
, tsp
, q
);
230 /* Clear the current information lines in both screens. */
231 MOVE(sp
, INFOLINE(sp
), 0);
233 MOVE(tsp
, INFOLINE(tsp
), 0);
236 /* Redraw the status line for the parent screen. */
237 (void)status(sp
, sp
->ep
, sp
->lno
, 0);
239 /* Save the parent screen's cursor information. */
240 sp
->frp
->lno
= sp
->lno
;
241 sp
->frp
->cno
= sp
->cno
;
242 F_SET(sp
->frp
, FR_CURSORSET
);
244 /* Completely redraw the child screen. */
245 F_SET(tsp
, S_REDRAW
);
247 /* Switch screens. */
249 F_SET(sp
, S_SSWITCH
);
252 /* Recover the original screen. */
254 *SVP(sp
) = saved_svp
;
256 /* Copy any (probably error) messages in the new screen. */
257 for (mp
= tsp
->msgq
.lh_first
; mp
!= NULL
; mp
= next
) {
258 if (!F_ISSET(mp
, M_EMPTY
))
260 mp
->flags
& M_INV_VIDEO
, mp
->mbuf
, mp
->len
);
261 next
= mp
->q
.le_next
;
262 if (mp
->mbuf
!= NULL
)
267 /* Free the new screen. */
270 FREE(tsp
, sizeof(SCR
));
276 * Background the screen, and switch to the next one.
284 /* Try and join with another screen. */
285 if ((svi_join(csp
, &sp
)))
289 "You may not background your only displayed screen.");
293 /* Move the old screen to the hidden queue. */
294 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
295 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
297 /* Switch screens. */
299 F_SET(csp
, S_SSWITCH
);
306 * Join the screen into a related screen, if one exists,
307 * and return that screen.
317 * If a split screen, add space to parent/child. Make no effort
318 * to clean up the screen's values. If it's not exiting, we'll
319 * get it when the user asks to show it again.
321 if ((sp
= csp
->q
.cqe_prev
) == (void *)&csp
->gp
->dq
) {
322 if ((sp
= csp
->q
.cqe_next
) == (void *)&csp
->gp
->dq
) {
326 sp
->woff
= csp
->woff
;
328 sp
->rows
+= csp
->rows
;
329 if (ISSMALLSCREEN(sp
)) {
330 sp
->t_maxrows
+= csp
->rows
;
331 for (cnt
= sp
->t_rows
; ++cnt
<= sp
->t_maxrows
;) {
335 TMAP
= HMAP
+ (sp
->t_rows
- 1);
337 sp
->t_maxrows
+= csp
->rows
;
338 sp
->t_rows
= sp
->t_minrows
= sp
->t_maxrows
;
339 TMAP
= HMAP
+ (sp
->t_rows
- 1);
340 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
346 * If the size of the scrolling region hasn't been modified by
347 * the user, reset it so it's reasonable for the new screen.
349 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
350 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
358 * Background the current screen, and foreground a new one.
367 if (svi_swap(csp
, &sp
, name
))
371 msgq(csp
, M_ERR
, "There are no background screens.");
374 "There's no background screen editing a file named %s.",
379 /* Move the old screen to the hidden queue. */
380 CIRCLEQ_REMOVE(&csp
->gp
->dq
, csp
, q
);
381 CIRCLEQ_INSERT_TAIL(&csp
->gp
->hq
, csp
, q
);
388 * Swap the current screen with a hidden one.
391 svi_swap(csp
, nsp
, name
)
398 /* Find the screen, or, if name is NULL, the first screen. */
399 for (sp
= csp
->gp
->hq
.cqh_first
;
400 sp
!= (void *)&csp
->gp
->hq
; sp
= sp
->q
.cqe_next
)
401 if (name
== NULL
|| !strcmp(FILENAME(sp
->frp
), name
))
403 if (sp
== (void *)&csp
->gp
->hq
) {
409 /* Save the old screen's cursor information. */
410 csp
->frp
->lno
= csp
->lno
;
411 csp
->frp
->cno
= csp
->cno
;
412 F_SET(csp
->frp
, FR_CURSORSET
);
414 /* Switch screens. */
416 F_SET(csp
, S_SSWITCH
);
418 /* Initialize terminal information. */
419 SVP(sp
)->srows
= SVP(csp
)->srows
;
421 issmallscreen
= ISSMALLSCREEN(sp
);
423 /* Initialize screen information. */
424 sp
->rows
= csp
->rows
;
425 sp
->cols
= csp
->cols
;
426 sp
->woff
= csp
->woff
;
429 * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b.
431 * The new screens may have different screen options sizes than the
432 * old one, so use them. Make sure that text counts aren't larger
433 * than the new screen sizes.
436 sp
->t_minrows
= sp
->t_rows
= O_VAL(sp
, O_WINDOW
);
437 if (sp
->t_rows
> csp
->t_maxrows
)
438 sp
->t_rows
= sp
->t_maxrows
;
439 if (sp
->t_minrows
> csp
->t_maxrows
)
440 sp
->t_minrows
= sp
->t_maxrows
;
442 sp
->t_rows
= sp
->t_maxrows
= sp
->t_minrows
= sp
->rows
- 1;
445 * If the size of the scrolling region hasn't been modified by
446 * the user, reset it so it's reasonable for the new screen.
448 if (!F_ISSET(&sp
->opts
[O_SCROLL
], OPT_SET
))
449 O_VAL(sp
, O_SCROLL
) = sp
->t_maxrows
/ 2;
452 * Don't change the screen's cursor information other than to
453 * note that the cursor is wrong.
455 F_SET(SVP(sp
), SVI_CUR_INVALID
);
458 * The HMAP may be NULL, if the screen got resized and
459 * a bunch of screens had to be hidden.
462 MALLOC_RET(sp
, HMAP
, SMAP
*, SIZE_HMAP(sp
) * sizeof(SMAP
));
463 TMAP
= HMAP
+ (sp
->t_rows
- 1);
466 if (svi_sm_fill(sp
, sp
->ep
, sp
->lno
, P_FILL
))
470 * The new screen replaces the old screen in the parent/child list.
471 * We insert the new screen after the old one. If we're exiting,
472 * the exit will delete the old one, if we're foregrounding, the fg
473 * code will move the old one to the hidden queue.
475 CIRCLEQ_REMOVE(&sp
->gp
->hq
, sp
, q
);
476 CIRCLEQ_INSERT_AFTER(&csp
->gp
->dq
, csp
, sp
, q
);
484 * Change the absolute size of the current screen.
494 * Figure out which screens will grow, which will shrink, and
495 * make sure it's possible.
502 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
504 if ((g
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
505 if ((g
= sp
->q
.cqe_next
) == (void *)&sp
->gp
->dq
)
512 if ((s
= sp
->q
.cqe_next
) != (void *)&sp
->gp
->dq
)
513 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
520 if ((s
= sp
->q
.cqe_prev
) == (void *)&sp
->gp
->dq
) {
521 toobig
: msgq(sp
, M_BERR
, "The screen cannot %s.",
522 count
< 0 ? "shrink" : "grow");
525 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
) {
526 toosmall
: msgq(sp
, M_BERR
,
527 "The screen can only shrink to %d rows.",
528 MINIMUM_SCREEN_ROWS
);
535 /* Update the screens. */
538 if (g
->t_minrows
== g
->t_maxrows
)
539 g
->t_minrows
+= count
;
540 g
->t_maxrows
+= count
;
541 _TMAP(g
) = _HMAP(g
) + (g
->t_rows
- 1);
542 (void)status(g
, g
->ep
, g
->lno
, 0);
547 s
->t_maxrows
-= count
;
548 if (s
->t_minrows
> s
->t_maxrows
)
549 s
->t_minrows
= s
->t_maxrows
;
550 _TMAP(s
) = _HMAP(s
) + (s
->t_rows
- 1);
551 (void)status(s
, s
->ep
, s
->lno
, 0);