1 /* $NetBSD: vs_split.c,v 1.2 2008/12/05 22:51:43 christos Exp $ */
4 * Copyright (c) 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
9 * See the LICENSE file for redistribution information.
15 static const char sccsid
[] = "Id: vs_split.c,v 10.42 2001/06/25 15:19:38 skimo Exp (Berkeley) Date: 2001/06/25 15:19:38";
18 #include <sys/types.h>
19 #include <sys/queue.h>
22 #include <bitstring.h>
29 #include "../common/common.h"
32 typedef enum { HORIZ_FOLLOW
, HORIZ_PRECEDE
, VERT_FOLLOW
, VERT_PRECEDE
} jdir_t
;
34 static SCR
*vs_getbg
__P((SCR
*, const char *));
35 static void vs_insert
__P((SCR
*sp
, WIN
*wp
));
36 static int vs_join
__P((SCR
*, SCR
**, jdir_t
*));
40 * Create a new screen, horizontally.
42 * PUBLIC: int vs_split __P((SCR *, SCR *, int));
45 vs_split(SCR
*sp
, SCR
*new, int ccl
)
47 /* Colon-command line split. */
52 int issmallscreen
, splitup
;
56 /* Check to see if it's possible. */
57 /* XXX: The IS_ONELINE fix will change this, too. */
60 "222|Screen must be larger than %d lines to split", 4 - 1);
64 /* Wait for any messages in the screen. */
65 vs_resolve(sp
, NULL
, 1);
67 /* Get a new screen map. */
68 CALLOC(sp
, _HMAP(new), SMAP
*, SIZE_HMAP(sp
), sizeof(SMAP
));
69 if (_HMAP(new) == NULL
)
71 _HMAP(new)->lno
= sp
->lno
;
75 /* Split the screen in half. */
81 * Small screens: see vs_refresh.c section 6a. Set a flag so
82 * we know to fix the screen up later.
84 issmallscreen
= IS_SMALL(sp
);
86 /* The columns in the screen don't change. */
91 * Split the screen, and link the screens together. If creating a
92 * screen to edit the colon command line or the cursor is in the top
93 * half of the current screen, the new screen goes under the current
94 * screen. Else, it goes above the current screen.
96 * Recalculate current cursor position based on sp->lno, we're called
97 * with the cursor on the colon command line. Then split the screen
98 * in half and update the shared information.
101 !ccl
&& (vs_sm_cursor(sp
, &smp
) ? 0 : (size_t)(smp
- HMAP
) + 1) >= half
;
102 if (splitup
) { /* Old is bottom half. */
103 new->rows
= sp
->rows
- half
; /* New. */
104 new->roff
= sp
->roff
;
105 sp
->rows
= half
; /* Old. */
106 sp
->roff
+= new->rows
;
109 * If the parent is the bottom half of the screen, shift
110 * the map down to match on-screen text.
112 memcpy(_HMAP(sp
), _HMAP(sp
) + new->rows
,
113 (sp
->t_maxrows
- new->rows
) * sizeof(SMAP
));
114 } else { /* Old is top half. */
115 new->rows
= half
; /* New. */
116 sp
->rows
-= half
; /* Old. */
117 new->roff
= sp
->roff
+ sp
->rows
;
120 /* Adjust maximum text count. */
121 sp
->t_maxrows
= IS_ONELINE(sp
) ? 1 : sp
->rows
- 1;
122 new->t_maxrows
= IS_ONELINE(new) ? 1 : new->rows
- 1;
125 * Small screens: see vs_refresh.c, section 6a.
127 * The child may have different screen options sizes than the parent,
128 * so use them. Guarantee that text counts aren't larger than the
132 /* Fix the text line count for the parent. */
134 sp
->t_rows
-= new->rows
;
136 /* Fix the parent screen. */
137 if (sp
->t_rows
> sp
->t_maxrows
)
138 sp
->t_rows
= sp
->t_maxrows
;
139 if (sp
->t_minrows
> sp
->t_maxrows
)
140 sp
->t_minrows
= sp
->t_maxrows
;
142 /* Fix the child screen. */
143 new->t_minrows
= new->t_rows
= O_VAL(sp
, O_WINDOW
);
144 if (new->t_rows
> new->t_maxrows
)
145 new->t_rows
= new->t_maxrows
;
146 if (new->t_minrows
> new->t_maxrows
)
147 new->t_minrows
= new->t_maxrows
;
149 sp
->t_minrows
= sp
->t_rows
= IS_ONELINE(sp
) ? 1 : sp
->rows
- 1;
152 * The new screen may be a small screen, even if the parent
153 * was not. Don't complain if O_WINDOW is too large, we're
154 * splitting the screen so the screen is much smaller than
157 new->t_minrows
= new->t_rows
= O_VAL(sp
, O_WINDOW
);
158 if (new->t_rows
> new->rows
- 1)
159 new->t_minrows
= new->t_rows
=
160 IS_ONELINE(new) ? 1 : new->rows
- 1;
163 /* Adjust the ends of the new and old maps. */
164 _TMAP(sp
) = IS_ONELINE(sp
) ?
165 _HMAP(sp
) : _HMAP(sp
) + (sp
->t_rows
- 1);
166 _TMAP(new) = IS_ONELINE(new) ?
167 _HMAP(new) : _HMAP(new) + (new->t_rows
- 1);
169 /* Reset the length of the default scroll. */
170 if ((sp
->defscroll
= sp
->t_maxrows
/ 2) == 0)
172 if ((new->defscroll
= new->t_maxrows
/ 2) == 0)
175 /* Fit the screen into the logical chain. */
176 vs_insert(new, sp
->wp
);
178 /* Tell the display that we're splitting. */
179 (void)gp
->scr_split(sp
, new);
182 * Initialize the screen flags:
184 * If we're in vi mode in one screen, we don't have to reinitialize.
185 * This isn't just a cosmetic fix. The path goes like this:
187 * return into vi(), SC_SSWITCH set
188 * call vs_refresh() with SC_STATUS set
189 * call vs_resolve to display the status message
190 * call vs_refresh() because the SC_SCR_VI bit isn't set
192 * Things go downhill at this point.
194 * Draw the new screen from scratch, and add a status line.
197 SC_SCR_REFORMAT
| SC_STATUS
|
198 F_ISSET(sp
, SC_EX
| SC_VI
| SC_SCR_VI
| SC_SCR_EX
));
204 * Create a new screen, vertically.
206 * PUBLIC: int vs_vsplit __P((SCR *, SCR *));
209 vs_vsplit(SCR
*sp
, SCR
*new)
216 /* Check to see if it's possible. */
217 if (sp
->cols
/ 2 <= MINIMUM_SCREEN_COLS
) {
219 "288|Screen must be larger than %d columns to split",
220 MINIMUM_SCREEN_COLS
* 2);
224 /* Wait for any messages in the screen. */
225 vs_resolve(sp
, NULL
, 1);
227 /* Get a new screen map. */
228 CALLOC(sp
, _HMAP(new), SMAP
*, SIZE_HMAP(sp
), sizeof(SMAP
));
229 if (_HMAP(new) == NULL
)
231 _HMAP(new)->lno
= sp
->lno
;
232 _HMAP(new)->coff
= 0;
233 _HMAP(new)->soff
= 1;
236 * Split the screen in half; we have to sacrifice a column to delimit
240 * We always split to the right... that makes more sense to me, and
241 * I don't want to play the stupid games that I play when splitting
245 * We reserve a column for the screen, "knowing" that curses needs
246 * one. This should be worked out with the display interface.
249 new->cols
= sp
->cols
- cols
- 1;
251 new->coff
= sp
->coff
+ cols
+ 1;
254 /* Nothing else changes. */
255 new->rows
= sp
->rows
;
256 new->t_rows
= sp
->t_rows
;
257 new->t_maxrows
= sp
->t_maxrows
;
258 new->t_minrows
= sp
->t_minrows
;
259 new->roff
= sp
->roff
;
260 new->defscroll
= sp
->defscroll
;
261 _TMAP(new) = _HMAP(new) + (new->t_rows
- 1);
263 /* Fit the screen into the logical chain. */
264 vs_insert(new, sp
->wp
);
266 /* Tell the display that we're splitting. */
267 (void)gp
->scr_split(sp
, new);
269 /* Redraw the old screen from scratch. */
270 F_SET(sp
, SC_SCR_REFORMAT
| SC_STATUS
);
273 * Initialize the screen flags:
275 * If we're in vi mode in one screen, we don't have to reinitialize.
276 * This isn't just a cosmetic fix. The path goes like this:
278 * return into vi(), SC_SSWITCH set
279 * call vs_refresh() with SC_STATUS set
280 * call vs_resolve to display the status message
281 * call vs_refresh() because the SC_SCR_VI bit isn't set
283 * Things go downhill at this point.
285 * Draw the new screen from scratch, and add a status line.
288 SC_SCR_REFORMAT
| SC_STATUS
|
289 F_ISSET(sp
, SC_EX
| SC_VI
| SC_SCR_VI
| SC_SCR_EX
));
295 * Insert the new screen into the correct place in the logical
299 vs_insert(SCR
*sp
, WIN
*wp
)
308 /* Move past all screens with lower row numbers. */
309 for (tsp
= wp
->scrq
.cqh_first
;
310 tsp
!= (void *)&wp
->scrq
; tsp
= tsp
->q
.cqe_next
)
311 if (tsp
->roff
>= sp
->roff
)
314 * Move past all screens with the same row number and lower
317 for (; tsp
!= (void *)&wp
->scrq
; tsp
= tsp
->q
.cqe_next
)
318 if (tsp
->roff
!= sp
->roff
|| tsp
->coff
> sp
->coff
)
322 * If we reached the end, this screen goes there. Otherwise,
323 * put it before or after the screen where we stopped.
325 if (tsp
== (void *)&wp
->scrq
) {
326 CIRCLEQ_INSERT_TAIL(&wp
->scrq
, sp
, q
);
327 } else if (tsp
->roff
< sp
->roff
||
328 (tsp
->roff
== sp
->roff
&& tsp
->coff
< sp
->coff
)) {
329 CIRCLEQ_INSERT_AFTER(&wp
->scrq
, tsp
, sp
, q
);
331 CIRCLEQ_INSERT_BEFORE(&wp
->scrq
, tsp
, sp
, q
);
336 * Discard the screen, folding the real-estate into a related screen,
337 * if one exists, and return that screen.
339 * PUBLIC: int vs_discard __P((SCR *, SCR **));
342 vs_discard(SCR
*sp
, SCR
**spp
)
345 SCR
*tsp
, **lp
, *list
[100];
351 * Save the old screen's cursor information.
354 * If called after file_end(), and the underlying file was a tmp
355 * file, it may have gone away.
357 if (sp
->frp
!= NULL
) {
358 sp
->frp
->lno
= sp
->lno
;
359 sp
->frp
->cno
= sp
->cno
;
360 F_SET(sp
->frp
, FR_CURSORSET
);
363 /* If no other screens to join, we're done. */
365 (void)gp
->scr_discard(sp
, NULL
);
373 * Find a set of screens that cover one of the screen's borders.
374 * Check the vertical axis first, for no particular reason.
377 * It's possible (I think?), to create a screen that shares no full
378 * border with any other set of screens, so we can't discard it. We
379 * just complain at the user until they clean it up.
381 if (vs_join(sp
, list
, &jdir
))
385 * Modify the affected screens. Redraw the modified screen(s) from
386 * scratch, setting a status line. If this is ever a performance
387 * problem we could play games with the map, but I wrote that code
388 * before and it was never clean or easy.
390 * Don't clean up the discarded screen's information. If the screen
391 * isn't exiting, we'll do the work when the user redisplays it.
396 for (lp
= &list
[0]; (tsp
= *lp
) != NULL
; ++lp
) {
398 * Small screens: see vs_refresh.c section 6a. Adjust
399 * text line info, unless it's a small screen.
401 * Reset the length of the default scroll.
403 * Reset the map references.
405 tsp
->rows
+= sp
->rows
;
407 tsp
->t_rows
= tsp
->t_minrows
= tsp
->rows
- 1;
408 tsp
->t_maxrows
= tsp
->rows
- 1;
410 tsp
->defscroll
= tsp
->t_maxrows
/ 2;
412 *(_HMAP(tsp
) + (tsp
->t_rows
- 1)) = *_TMAP(tsp
);
413 _TMAP(tsp
) = _HMAP(tsp
) + (tsp
->t_rows
- 1);
417 tsp
->roff
= sp
->roff
;
418 vs_sm_fill(tsp
, OOBLNO
, P_TOP
);
421 vs_sm_fill(tsp
, OOBLNO
, P_BOTTOM
);
426 F_SET(tsp
, SC_STATUS
);
431 for (lp
= &list
[0]; (tsp
= *lp
) != NULL
; ++lp
) {
432 if (jdir
== VERT_FOLLOW
)
433 tsp
->coff
= sp
->coff
;
434 tsp
->cols
+= sp
->cols
+ 1; /* XXX: DIVIDER */
435 vs_sm_fill(tsp
, OOBLNO
, P_TOP
);
436 F_SET(tsp
, SC_STATUS
);
443 /* Find the closest screen that changed and move to it. */
448 /* Tell the display that we're discarding a screen. */
449 (void)gp
->scr_discard(sp
, list
);
456 * Find a set of screens that covers a screen's border.
459 vs_join(SCR
*sp
, SCR
**listp
, jdir_t
*jdirp
)
470 /* Check preceding vertical. */
471 for (lp
= listp
, tlen
= sp
->rows
,
472 tsp
= wp
->scrq
.cqh_first
;
473 tsp
!= (void *)&wp
->scrq
; tsp
= tsp
->q
.cqe_next
) {
476 /* Test if precedes the screen vertically. */
477 if (tsp
->coff
+ tsp
->cols
+ 1 != sp
->coff
)
480 * Test if a subset on the vertical axis. If overlaps the
481 * beginning or end, we can't join on this axis at all.
483 if (tsp
->roff
> sp
->roff
+ sp
->rows
)
485 if (tsp
->roff
< sp
->roff
) {
486 if (tsp
->roff
+ tsp
->rows
>= sp
->roff
)
490 if (tsp
->roff
+ tsp
->rows
> sp
->roff
+ sp
->rows
)
493 if (tlen
< tsp
->rows
)
501 *jdirp
= VERT_PRECEDE
;
505 /* Check following vertical. */
506 for (lp
= listp
, tlen
= sp
->rows
,
507 tsp
= wp
->scrq
.cqh_first
;
508 tsp
!= (void *)&wp
->scrq
; tsp
= tsp
->q
.cqe_next
) {
511 /* Test if follows the screen vertically. */
512 if (tsp
->coff
!= sp
->coff
+ sp
->cols
+ 1)
515 * Test if a subset on the vertical axis. If overlaps the
516 * beginning or end, we can't join on this axis at all.
518 if (tsp
->roff
> sp
->roff
+ sp
->rows
)
520 if (tsp
->roff
< sp
->roff
) {
521 if (tsp
->roff
+ tsp
->rows
>= sp
->roff
)
525 if (tsp
->roff
+ tsp
->rows
> sp
->roff
+ sp
->rows
)
528 if (tlen
< tsp
->rows
)
536 *jdirp
= VERT_FOLLOW
;
540 /* Check preceding horizontal. */
541 for (first
= 0, lp
= listp
, tlen
= sp
->cols
,
542 tsp
= wp
->scrq
.cqh_first
;
543 tsp
!= (void *)&wp
->scrq
; tsp
= tsp
->q
.cqe_next
) {
546 /* Test if precedes the screen horizontally. */
547 if (tsp
->roff
+ tsp
->rows
!= sp
->roff
)
550 * Test if a subset on the horizontal axis. If overlaps the
551 * beginning or end, we can't join on this axis at all.
553 if (tsp
->coff
> sp
->coff
+ sp
->cols
)
555 if (tsp
->coff
< sp
->coff
) {
556 if (tsp
->coff
+ tsp
->cols
>= sp
->coff
)
560 if (tsp
->coff
+ tsp
->cols
> sp
->coff
+ sp
->cols
)
563 if (tlen
< tsp
->cols
)
566 tlen
-= tsp
->cols
+ first
;
572 *jdirp
= HORIZ_PRECEDE
;
576 /* Check following horizontal. */
577 for (first
= 0, lp
= listp
, tlen
= sp
->cols
,
578 tsp
= wp
->scrq
.cqh_first
;
579 tsp
!= (void *)&wp
->scrq
; tsp
= tsp
->q
.cqe_next
) {
582 /* Test if precedes the screen horizontally. */
583 if (tsp
->roff
!= sp
->roff
+ sp
->rows
)
586 * Test if a subset on the horizontal axis. If overlaps the
587 * beginning or end, we can't join on this axis at all.
589 if (tsp
->coff
> sp
->coff
+ sp
->cols
)
591 if (tsp
->coff
< sp
->coff
) {
592 if (tsp
->coff
+ tsp
->cols
>= sp
->coff
)
596 if (tsp
->coff
+ tsp
->cols
> sp
->coff
+ sp
->cols
)
599 if (tlen
< tsp
->cols
)
602 tlen
-= tsp
->cols
+ first
;
608 *jdirp
= HORIZ_FOLLOW
;
616 * Background the current screen, and foreground a new one.
618 * PUBLIC: int vs_fg __P((SCR *, SCR **, CHAR_T *, int));
621 vs_fg(SCR
*sp
, SCR
**nspp
, CHAR_T
*name
, int newscreen
)
633 INT2CHAR(sp
, name
, STRLEN(name
) + 1, np
, nlen
);
637 /* Get the specified background screen. */
638 nsp
= vs_getbg(sp
, np
);
641 if (vs_swap(sp
, &nsp
, np
))
644 if ((*nspp
= nsp
) == NULL
) {
645 msgq_wstr(sp
, M_ERR
, name
,
647 "223|There are no background screens" :
648 "224|There's no background screen editing a file named %s");
653 /* Remove the new screen from the background queue. */
654 CIRCLEQ_REMOVE(&gp
->hq
, nsp
, q
);
656 /* Split the screen; if we fail, hook the screen back in. */
657 if (vs_split(sp
, nsp
, 0)) {
658 CIRCLEQ_INSERT_TAIL(&gp
->hq
, nsp
, q
);
662 /* Move the old screen to the background queue. */
663 CIRCLEQ_REMOVE(&wp
->scrq
, sp
, q
);
664 CIRCLEQ_INSERT_TAIL(&gp
->hq
, sp
, q
);
671 * Background the screen, and switch to the next one.
673 * PUBLIC: int vs_bg __P((SCR *));
685 /* Try and join with another screen. */
686 if (vs_discard(sp
, &nsp
))
690 "225|You may not background your only displayed screen");
694 /* Move the old screen to the background queue. */
695 CIRCLEQ_REMOVE(&wp
->scrq
, sp
, q
);
696 CIRCLEQ_INSERT_TAIL(&gp
->hq
, sp
, q
);
698 /* Toss the screen map. */
702 /* Switch screens. */
704 F_SET(sp
, SC_SSWITCH
);
711 * Swap the current screen with a backgrounded one.
713 * PUBLIC: int vs_swap __P((SCR *, SCR **, const char *));
716 vs_swap(SCR
*sp
, SCR
**nspp
, const char *name
)
725 /* Get the specified background screen. */
726 if ((*nspp
= nsp
= vs_getbg(sp
, name
)) == NULL
)
730 * Save the old screen's cursor information.
733 * If called after file_end(), and the underlying file was a tmp
734 * file, it may have gone away.
736 if (sp
->frp
!= NULL
) {
737 sp
->frp
->lno
= sp
->lno
;
738 sp
->frp
->cno
= sp
->cno
;
739 F_SET(sp
->frp
, FR_CURSORSET
);
742 /* Switch screens. */
744 F_SET(sp
, SC_SSWITCH
);
746 /* Initialize terminal information. */
747 VIP(nsp
)->srows
= VIP(sp
)->srows
;
749 /* Initialize screen information. */
750 nsp
->cols
= sp
->cols
;
751 nsp
->rows
= sp
->rows
; /* XXX: Only place in vi that sets rows. */
752 nsp
->roff
= sp
->roff
;
755 * Small screens: see vs_refresh.c, section 6a.
757 * The new screens may have different screen options sizes than the
758 * old one, so use them. Make sure that text counts aren't larger
759 * than the new screen sizes.
762 nsp
->t_minrows
= nsp
->t_rows
= O_VAL(nsp
, O_WINDOW
);
763 if (nsp
->t_rows
> sp
->t_maxrows
)
764 nsp
->t_rows
= nsp
->t_maxrows
;
765 if (nsp
->t_minrows
> sp
->t_maxrows
)
766 nsp
->t_minrows
= nsp
->t_maxrows
;
768 nsp
->t_rows
= nsp
->t_maxrows
= nsp
->t_minrows
= nsp
->rows
- 1;
770 /* Reset the length of the default scroll. */
771 nsp
->defscroll
= nsp
->t_maxrows
/ 2;
773 /* Allocate a new screen map. */
774 CALLOC_RET(nsp
, _HMAP(nsp
), SMAP
*, SIZE_HMAP(nsp
), sizeof(SMAP
));
775 _TMAP(nsp
) = _HMAP(nsp
) + (nsp
->t_rows
- 1);
779 if (vs_sm_fill(nsp
, nsp
->lno
, P_FILL
))
783 * The new screen replaces the old screen in the parent/child list.
784 * We insert the new screen after the old one. If we're exiting,
785 * the exit will delete the old one, if we're foregrounding, the fg
786 * code will move the old one to the background queue.
788 CIRCLEQ_REMOVE(&gp
->hq
, nsp
, q
);
789 CIRCLEQ_INSERT_AFTER(&wp
->scrq
, sp
, nsp
, q
);
792 * Don't change the screen's cursor information other than to
793 * note that the cursor is wrong.
795 F_SET(VIP(nsp
), VIP_CUR_INVALID
);
797 /* Draw the new screen from scratch, and add a status line. */
798 F_SET(nsp
, SC_SCR_REDRAW
| SC_STATUS
);
800 list
[0] = nsp
; list
[1] = NULL
;
801 (void)gp
->scr_discard(sp
, list
);
808 * Change the absolute size of the current screen.
810 * PUBLIC: int vs_resize __P((SCR *, long, adj_t));
813 vs_resize(SCR
*sp
, long int count
, adj_t adj
)
817 SCR
*g
, *s
, *prev
, *next
, *list
[3] = {NULL
, NULL
, NULL
};
824 * Figure out which screens will grow, which will shrink, and
825 * make sure it's possible.
830 if (sp
->t_maxrows
== (size_t)count
)
832 if (sp
->t_maxrows
> (size_t)count
) {
834 count
= sp
->t_maxrows
- count
;
837 count
= count
- sp
->t_maxrows
;
841 /* Find first overlapping screen */
842 for (next
= sp
->q
.cqe_next
;
843 next
!= (void *)&wp
->scrq
&&
844 (next
->coff
>= sp
->coff
+ sp
->cols
||
845 next
->coff
+ next
->cols
<= sp
->coff
);
846 next
= next
->q
.cqe_next
);
847 /* See if we can use it */
848 if (next
!= (void *)&wp
->scrq
&&
849 (sp
->coff
!= next
->coff
|| sp
->cols
!= next
->cols
))
850 next
= (void *)&wp
->scrq
;
851 for (prev
= sp
->q
.cqe_prev
;
852 prev
!= (void *)&wp
->scrq
&&
853 (prev
->coff
>= sp
->coff
+ sp
->cols
||
854 prev
->coff
+ prev
->cols
<= sp
->coff
);
855 prev
= prev
->q
.cqe_prev
);
856 if (prev
!= (void *)&wp
->scrq
&&
857 (sp
->coff
!= prev
->coff
|| sp
->cols
!= prev
->cols
))
858 prev
= (void *)&wp
->scrq
;
861 if (adj
== A_DECREASE
) {
865 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ (size_t)count
)
867 if ((g
= prev
) == (void *)&wp
->scrq
) {
868 if ((g
= next
) == (void *)&wp
->scrq
)
875 if ((s
= next
) != (void *)&wp
->scrq
&&
876 s
->t_maxrows
>= MINIMUM_SCREEN_ROWS
+ (size_t)count
)
881 if ((s
= prev
) == (void *)&wp
->scrq
) {
882 toobig
: msgq(sp
, M_BERR
, adj
== A_DECREASE
?
883 "227|The screen cannot shrink" :
884 "228|The screen cannot grow");
887 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ (size_t)count
) {
888 toosmall
: msgq(sp
, M_BERR
,
889 "226|The screen can only shrink to %d rows",
890 MINIMUM_SCREEN_ROWS
);
898 * Fix up the screens; we could optimize the reformatting of the
899 * screen, but this isn't likely to be a common enough operation
900 * to make it worthwhile.
908 if (g
->t_minrows
== g
->t_maxrows
)
909 g
->t_minrows
+= count
;
910 g
->t_maxrows
+= count
;
912 F_SET(g
, SC_SCR_REFORMAT
| SC_STATUS
);
915 s
->t_maxrows
-= count
;
916 if (s
->t_minrows
> s
->t_maxrows
)
917 s
->t_minrows
= s
->t_maxrows
;
919 F_SET(s
, SC_SCR_REFORMAT
| SC_STATUS
);
922 list
[0] = g
; list
[1] = s
;
923 gp
->scr_discard(0, list
);
930 * Get the specified background screen, or, if name is NULL, the first
934 vs_getbg(SCR
*sp
, const char *name
)
942 /* If name is NULL, return the first background screen on the list. */
944 nsp
= gp
->hq
.cqh_first
;
945 return (nsp
== (void *)&gp
->hq
? NULL
: nsp
);
948 /* Search for a full match. */
949 for (nsp
= gp
->hq
.cqh_first
;
950 nsp
!= (void *)&gp
->hq
; nsp
= nsp
->q
.cqe_next
)
951 if (!strcmp(nsp
->frp
->name
, name
))
953 if (nsp
!= (void *)&gp
->hq
)
956 /* Search for a last-component match. */
957 for (nsp
= gp
->hq
.cqh_first
;
958 nsp
!= (void *)&gp
->hq
; nsp
= nsp
->q
.cqe_next
) {
959 if ((p
= strrchr(nsp
->frp
->name
, '/')) == NULL
)
963 if (!strcmp(p
, name
))
966 if (nsp
!= (void *)&gp
->hq
)