1 |
|
|
/* $OpenBSD: vs_split.c,v 1.16 2016/05/27 09:18:12 martijn Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
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. |
8 |
|
|
* |
9 |
|
|
* See the LICENSE file for redistribution information. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
#include "config.h" |
13 |
|
|
|
14 |
|
|
#include <sys/types.h> |
15 |
|
|
#include <sys/queue.h> |
16 |
|
|
#include <sys/time.h> |
17 |
|
|
|
18 |
|
|
#include <bitstring.h> |
19 |
|
|
#include <errno.h> |
20 |
|
|
#include <limits.h> |
21 |
|
|
#include <stdio.h> |
22 |
|
|
#include <stdlib.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
|
25 |
|
|
#include "../common/common.h" |
26 |
|
|
#include "vi.h" |
27 |
|
|
|
28 |
|
|
static SCR *vs_getbg(SCR *, char *); |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
* vs_split -- |
32 |
|
|
* Create a new screen. |
33 |
|
|
* |
34 |
|
|
* PUBLIC: int vs_split(SCR *, SCR *, int); |
35 |
|
|
*/ |
36 |
|
|
int |
37 |
|
|
vs_split(SCR *sp, SCR *new, int ccl) |
38 |
|
|
{ |
39 |
|
|
GS *gp; |
40 |
|
|
SMAP *smp; |
41 |
|
|
size_t half; |
42 |
|
|
int issmallscreen, splitup; |
43 |
|
|
|
44 |
|
|
gp = sp->gp; |
45 |
|
|
|
46 |
|
|
/* Check to see if it's possible. */ |
47 |
|
|
/* XXX: The IS_ONELINE fix will change this, too. */ |
48 |
|
|
if (sp->rows < 4) { |
49 |
|
|
msgq(sp, M_ERR, |
50 |
|
|
"Screen must be larger than %d lines to split", 4 - 1); |
51 |
|
|
return (1); |
52 |
|
|
} |
53 |
|
|
|
54 |
|
|
/* Wait for any messages in the screen. */ |
55 |
|
|
vs_resolve(sp, NULL, 1); |
56 |
|
|
|
57 |
|
|
half = sp->rows / 2; |
58 |
|
|
if (ccl && half > 6) |
59 |
|
|
half = 6; |
60 |
|
|
|
61 |
|
|
/* Get a new screen map. */ |
62 |
|
|
CALLOC(sp, _HMAP(new), SIZE_HMAP(sp), sizeof(SMAP)); |
63 |
|
|
if (_HMAP(new) == NULL) |
64 |
|
|
return (1); |
65 |
|
|
_HMAP(new)->lno = sp->lno; |
66 |
|
|
_HMAP(new)->coff = 0; |
67 |
|
|
_HMAP(new)->soff = 1; |
68 |
|
|
|
69 |
|
|
/* |
70 |
|
|
* Small screens: see vs_refresh.c section 6a. Set a flag so |
71 |
|
|
* we know to fix the screen up later. |
72 |
|
|
*/ |
73 |
|
|
issmallscreen = IS_SMALL(sp); |
74 |
|
|
|
75 |
|
|
/* The columns in the screen don't change. */ |
76 |
|
|
new->cols = sp->cols; |
77 |
|
|
|
78 |
|
|
/* |
79 |
|
|
* Split the screen, and link the screens together. If creating a |
80 |
|
|
* screen to edit the colon command line or the cursor is in the top |
81 |
|
|
* half of the current screen, the new screen goes under the current |
82 |
|
|
* screen. Else, it goes above the current screen. |
83 |
|
|
* |
84 |
|
|
* Recalculate current cursor position based on sp->lno, we're called |
85 |
|
|
* with the cursor on the colon command line. Then split the screen |
86 |
|
|
* in half and update the shared information. |
87 |
|
|
*/ |
88 |
|
|
splitup = |
89 |
|
|
!ccl && (vs_sm_cursor(sp, &smp) ? 0 : (smp - HMAP) + 1) >= half; |
90 |
|
|
if (splitup) { /* Old is bottom half. */ |
91 |
|
|
new->rows = sp->rows - half; /* New. */ |
92 |
|
|
new->woff = sp->woff; |
93 |
|
|
sp->rows = half; /* Old. */ |
94 |
|
|
sp->woff += new->rows; |
95 |
|
|
/* Link in before old. */ |
96 |
|
|
TAILQ_INSERT_BEFORE(sp, new, q); |
97 |
|
|
|
98 |
|
|
/* |
99 |
|
|
* If the parent is the bottom half of the screen, shift |
100 |
|
|
* the map down to match on-screen text. |
101 |
|
|
*/ |
102 |
|
|
memmove(_HMAP(sp), _HMAP(sp) + new->rows, |
103 |
|
|
(sp->t_maxrows - new->rows) * sizeof(SMAP)); |
104 |
|
|
} else { /* Old is top half. */ |
105 |
|
|
new->rows = half; /* New. */ |
106 |
|
|
sp->rows -= half; /* Old. */ |
107 |
|
|
new->woff = sp->woff + sp->rows; |
108 |
|
|
/* Link in after old. */ |
109 |
|
|
TAILQ_INSERT_AFTER(&gp->dq, sp, new, q); |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
/* Adjust maximum text count. */ |
113 |
|
|
sp->t_maxrows = IS_ONELINE(sp) ? 1 : sp->rows - 1; |
114 |
|
|
new->t_maxrows = IS_ONELINE(new) ? 1 : new->rows - 1; |
115 |
|
|
|
116 |
|
|
/* |
117 |
|
|
* Small screens: see vs_refresh.c, section 6a. |
118 |
|
|
* |
119 |
|
|
* The child may have different screen options sizes than the parent, |
120 |
|
|
* so use them. Guarantee that text counts aren't larger than the |
121 |
|
|
* new screen sizes. |
122 |
|
|
*/ |
123 |
|
|
if (issmallscreen) { |
124 |
|
|
/* Fix the text line count for the parent. */ |
125 |
|
|
if (splitup) |
126 |
|
|
sp->t_rows -= new->rows; |
127 |
|
|
|
128 |
|
|
/* Fix the parent screen. */ |
129 |
|
|
if (sp->t_rows > sp->t_maxrows) |
130 |
|
|
sp->t_rows = sp->t_maxrows; |
131 |
|
|
if (sp->t_minrows > sp->t_maxrows) |
132 |
|
|
sp->t_minrows = sp->t_maxrows; |
133 |
|
|
|
134 |
|
|
/* Fix the child screen. */ |
135 |
|
|
new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW); |
136 |
|
|
if (new->t_rows > new->t_maxrows) |
137 |
|
|
new->t_rows = new->t_maxrows; |
138 |
|
|
if (new->t_minrows > new->t_maxrows) |
139 |
|
|
new->t_minrows = new->t_maxrows; |
140 |
|
|
} else { |
141 |
|
|
sp->t_minrows = sp->t_rows = IS_ONELINE(sp) ? 1 : sp->rows - 1; |
142 |
|
|
|
143 |
|
|
/* |
144 |
|
|
* The new screen may be a small screen, even if the parent |
145 |
|
|
* was not. Don't complain if O_WINDOW is too large, we're |
146 |
|
|
* splitting the screen so the screen is much smaller than |
147 |
|
|
* normal. |
148 |
|
|
*/ |
149 |
|
|
new->t_minrows = new->t_rows = O_VAL(sp, O_WINDOW); |
150 |
|
|
if (new->t_rows > new->rows - 1) |
151 |
|
|
new->t_minrows = new->t_rows = |
152 |
|
|
IS_ONELINE(new) ? 1 : new->rows - 1; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
/* Adjust the ends of the new and old maps. */ |
156 |
|
|
_TMAP(sp) = IS_ONELINE(sp) ? |
157 |
|
|
_HMAP(sp) : _HMAP(sp) + (sp->t_rows - 1); |
158 |
|
|
_TMAP(new) = IS_ONELINE(new) ? |
159 |
|
|
_HMAP(new) : _HMAP(new) + (new->t_rows - 1); |
160 |
|
|
|
161 |
|
|
/* Reset the length of the default scroll. */ |
162 |
|
|
if ((sp->defscroll = sp->t_maxrows / 2) == 0) |
163 |
|
|
sp->defscroll = 1; |
164 |
|
|
if ((new->defscroll = new->t_maxrows / 2) == 0) |
165 |
|
|
new->defscroll = 1; |
166 |
|
|
|
167 |
|
|
/* |
168 |
|
|
* Initialize the screen flags: |
169 |
|
|
* |
170 |
|
|
* If we're in vi mode in one screen, we don't have to reinitialize. |
171 |
|
|
* This isn't just a cosmetic fix. The path goes like this: |
172 |
|
|
* |
173 |
|
|
* return into vi(), SC_SSWITCH set |
174 |
|
|
* call vs_refresh() with SC_STATUS set |
175 |
|
|
* call vs_resolve to display the status message |
176 |
|
|
* call vs_refresh() because the SC_SCR_VI bit isn't set |
177 |
|
|
* |
178 |
|
|
* Things go downhill at this point. |
179 |
|
|
* |
180 |
|
|
* Draw the new screen from scratch, and add a status line. |
181 |
|
|
*/ |
182 |
|
|
F_SET(new, |
183 |
|
|
SC_SCR_REFORMAT | SC_STATUS | |
184 |
|
|
F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX)); |
185 |
|
|
return (0); |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
/* |
189 |
|
|
* vs_discard -- |
190 |
|
|
* Discard the screen, folding the real-estate into a related screen, |
191 |
|
|
* if one exists, and return that screen. |
192 |
|
|
* |
193 |
|
|
* PUBLIC: int vs_discard(SCR *, SCR **); |
194 |
|
|
*/ |
195 |
|
|
int |
196 |
|
|
vs_discard(SCR *sp, SCR **spp) |
197 |
|
|
{ |
198 |
|
|
SCR *nsp; |
199 |
|
|
dir_t dir; |
200 |
|
|
|
201 |
|
|
/* |
202 |
|
|
* Save the old screen's cursor information. |
203 |
|
|
* |
204 |
|
|
* XXX |
205 |
|
|
* If called after file_end(), and the underlying file was a tmp |
206 |
|
|
* file, it may have gone away. |
207 |
|
|
*/ |
208 |
|
|
if (sp->frp != NULL) { |
209 |
|
|
sp->frp->lno = sp->lno; |
210 |
|
|
sp->frp->cno = sp->cno; |
211 |
|
|
F_SET(sp->frp, FR_CURSORSET); |
212 |
|
|
} |
213 |
|
|
|
214 |
|
|
/* |
215 |
|
|
* Add into a previous screen and then into a subsequent screen, as |
216 |
|
|
* they're the closest to the current screen. If that doesn't work, |
217 |
|
|
* there was no screen to join. |
218 |
|
|
*/ |
219 |
|
|
if ((nsp = TAILQ_PREV(sp, _dqh, q))) { |
220 |
|
|
nsp->rows += sp->rows; |
221 |
|
|
sp = nsp; |
222 |
|
|
dir = FORWARD; |
223 |
|
|
} else if ((nsp = TAILQ_NEXT(sp, q))) { |
224 |
|
|
nsp->woff = sp->woff; |
225 |
|
|
nsp->rows += sp->rows; |
226 |
|
|
sp = nsp; |
227 |
|
|
dir = BACKWARD; |
228 |
|
|
} else { |
229 |
|
|
sp = NULL; |
230 |
|
|
dir = 0; /* unused */ |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
if (spp != NULL) |
234 |
|
|
*spp = sp; |
235 |
|
|
if (sp == NULL) |
236 |
|
|
return (0); |
237 |
|
|
|
238 |
|
|
/* |
239 |
|
|
* Make no effort to clean up the discarded screen's information. If |
240 |
|
|
* it's not exiting, we'll do the work when the user redisplays it. |
241 |
|
|
* |
242 |
|
|
* Small screens: see vs_refresh.c section 6a. Adjust text line info, |
243 |
|
|
* unless it's a small screen. |
244 |
|
|
* |
245 |
|
|
* Reset the length of the default scroll. |
246 |
|
|
*/ |
247 |
|
|
if (!IS_SMALL(sp)) |
248 |
|
|
sp->t_rows = sp->t_minrows = sp->rows - 1; |
249 |
|
|
sp->t_maxrows = sp->rows - 1; |
250 |
|
|
sp->defscroll = sp->t_maxrows / 2; |
251 |
|
|
*(HMAP + (sp->t_rows - 1)) = *TMAP; |
252 |
|
|
TMAP = HMAP + (sp->t_rows - 1); |
253 |
|
|
|
254 |
|
|
/* |
255 |
|
|
* Draw the new screen from scratch, and add a status line. |
256 |
|
|
* |
257 |
|
|
* XXX |
258 |
|
|
* We could play games with the map, if this were ever to be a |
259 |
|
|
* performance problem, but I wrote the code a few times and it |
260 |
|
|
* was never clean or easy. |
261 |
|
|
*/ |
262 |
|
|
switch (dir) { |
263 |
|
|
case FORWARD: |
264 |
|
|
vs_sm_fill(sp, OOBLNO, P_TOP); |
265 |
|
|
break; |
266 |
|
|
case BACKWARD: |
267 |
|
|
vs_sm_fill(sp, OOBLNO, P_BOTTOM); |
268 |
|
|
break; |
269 |
|
|
default: |
270 |
|
|
abort(); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
F_SET(sp, SC_STATUS); |
274 |
|
|
return (0); |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
/* |
278 |
|
|
* vs_fg -- |
279 |
|
|
* Background the current screen, and foreground a new one. |
280 |
|
|
* |
281 |
|
|
* PUBLIC: int vs_fg(SCR *, SCR **, CHAR_T *, int); |
282 |
|
|
*/ |
283 |
|
|
int |
284 |
|
|
vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen) |
285 |
|
|
{ |
286 |
|
|
GS *gp; |
287 |
|
|
SCR *nsp; |
288 |
|
|
|
289 |
|
|
gp = sp->gp; |
290 |
|
|
|
291 |
|
|
if (newscreen) |
292 |
|
|
/* Get the specified background screen. */ |
293 |
|
|
nsp = vs_getbg(sp, name); |
294 |
|
|
else |
295 |
|
|
/* Swap screens. */ |
296 |
|
|
if (vs_swap(sp, &nsp, name)) |
297 |
|
|
return (1); |
298 |
|
|
|
299 |
|
|
if ((*nspp = nsp) == NULL) { |
300 |
|
|
msgq_str(sp, M_ERR, name, |
301 |
|
|
name == NULL ? |
302 |
|
|
"There are no background screens" : |
303 |
|
|
"There's no background screen editing a file named %s"); |
304 |
|
|
return (1); |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
if (newscreen) { |
308 |
|
|
/* Remove the new screen from the background queue. */ |
309 |
|
|
TAILQ_REMOVE(&gp->hq, nsp, q); |
310 |
|
|
|
311 |
|
|
/* Split the screen; if we fail, hook the screen back in. */ |
312 |
|
|
if (vs_split(sp, nsp, 0)) { |
313 |
|
|
TAILQ_INSERT_TAIL(&gp->hq, nsp, q); |
314 |
|
|
return (1); |
315 |
|
|
} |
316 |
|
|
} else { |
317 |
|
|
/* Move the old screen to the background queue. */ |
318 |
|
|
TAILQ_REMOVE(&gp->dq, sp, q); |
319 |
|
|
TAILQ_INSERT_TAIL(&gp->hq, sp, q); |
320 |
|
|
} |
321 |
|
|
return (0); |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
/* |
325 |
|
|
* vs_bg -- |
326 |
|
|
* Background the screen, and switch to the next one. |
327 |
|
|
* |
328 |
|
|
* PUBLIC: int vs_bg(SCR *); |
329 |
|
|
*/ |
330 |
|
|
int |
331 |
|
|
vs_bg(SCR *sp) |
332 |
|
|
{ |
333 |
|
|
GS *gp; |
334 |
|
|
SCR *nsp; |
335 |
|
|
|
336 |
|
|
gp = sp->gp; |
337 |
|
|
|
338 |
|
|
/* Try and join with another screen. */ |
339 |
|
|
if (vs_discard(sp, &nsp)) |
340 |
|
|
return (1); |
341 |
|
|
if (nsp == NULL) { |
342 |
|
|
msgq(sp, M_ERR, |
343 |
|
|
"You may not background your only displayed screen"); |
344 |
|
|
return (1); |
345 |
|
|
} |
346 |
|
|
|
347 |
|
|
/* Move the old screen to the background queue. */ |
348 |
|
|
TAILQ_REMOVE(&gp->dq, sp, q); |
349 |
|
|
TAILQ_INSERT_TAIL(&gp->hq, sp, q); |
350 |
|
|
|
351 |
|
|
/* Toss the screen map. */ |
352 |
|
|
free(_HMAP(sp)); |
353 |
|
|
_HMAP(sp) = NULL; |
354 |
|
|
|
355 |
|
|
/* Switch screens. */ |
356 |
|
|
sp->nextdisp = nsp; |
357 |
|
|
F_SET(sp, SC_SSWITCH); |
358 |
|
|
|
359 |
|
|
return (0); |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
/* |
363 |
|
|
* vs_swap -- |
364 |
|
|
* Swap the current screen with a backgrounded one. |
365 |
|
|
* |
366 |
|
|
* PUBLIC: int vs_swap(SCR *, SCR **, char *); |
367 |
|
|
*/ |
368 |
|
|
int |
369 |
|
|
vs_swap(SCR *sp, SCR **nspp, char *name) |
370 |
|
|
{ |
371 |
|
|
GS *gp; |
372 |
|
|
SCR *nsp; |
373 |
|
|
|
374 |
|
|
gp = sp->gp; |
375 |
|
|
|
376 |
|
|
/* Get the specified background screen. */ |
377 |
|
|
if ((*nspp = nsp = vs_getbg(sp, name)) == NULL) |
378 |
|
|
return (0); |
379 |
|
|
|
380 |
|
|
/* |
381 |
|
|
* Save the old screen's cursor information. |
382 |
|
|
* |
383 |
|
|
* XXX |
384 |
|
|
* If called after file_end(), and the underlying file was a tmp |
385 |
|
|
* file, it may have gone away. |
386 |
|
|
*/ |
387 |
|
|
if (sp->frp != NULL) { |
388 |
|
|
sp->frp->lno = sp->lno; |
389 |
|
|
sp->frp->cno = sp->cno; |
390 |
|
|
F_SET(sp->frp, FR_CURSORSET); |
391 |
|
|
} |
392 |
|
|
|
393 |
|
|
/* Switch screens. */ |
394 |
|
|
sp->nextdisp = nsp; |
395 |
|
|
F_SET(sp, SC_SSWITCH); |
396 |
|
|
|
397 |
|
|
/* Initialize terminal information. */ |
398 |
|
|
VIP(nsp)->srows = VIP(sp)->srows; |
399 |
|
|
|
400 |
|
|
/* Initialize screen information. */ |
401 |
|
|
nsp->cols = sp->cols; |
402 |
|
|
nsp->rows = sp->rows; /* XXX: Only place in vi that sets rows. */ |
403 |
|
|
nsp->woff = sp->woff; |
404 |
|
|
|
405 |
|
|
/* |
406 |
|
|
* Small screens: see vs_refresh.c, section 6a. |
407 |
|
|
* |
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. |
411 |
|
|
*/ |
412 |
|
|
if (IS_SMALL(nsp)) { |
413 |
|
|
nsp->t_minrows = nsp->t_rows = O_VAL(nsp, O_WINDOW); |
414 |
|
|
if (nsp->t_rows > sp->t_maxrows) |
415 |
|
|
nsp->t_rows = nsp->t_maxrows; |
416 |
|
|
if (nsp->t_minrows > sp->t_maxrows) |
417 |
|
|
nsp->t_minrows = nsp->t_maxrows; |
418 |
|
|
} else |
419 |
|
|
nsp->t_rows = nsp->t_maxrows = nsp->t_minrows = nsp->rows - 1; |
420 |
|
|
|
421 |
|
|
/* Reset the length of the default scroll. */ |
422 |
|
|
nsp->defscroll = nsp->t_maxrows / 2; |
423 |
|
|
|
424 |
|
|
/* Allocate a new screen map. */ |
425 |
|
|
CALLOC_RET(nsp, _HMAP(nsp), SIZE_HMAP(nsp), sizeof(SMAP)); |
426 |
|
|
_TMAP(nsp) = _HMAP(nsp) + (nsp->t_rows - 1); |
427 |
|
|
|
428 |
|
|
/* Fill the map. */ |
429 |
|
|
if (vs_sm_fill(nsp, nsp->lno, P_FILL)) |
430 |
|
|
return (1); |
431 |
|
|
|
432 |
|
|
/* |
433 |
|
|
* The new screen replaces the old screen in the parent/child list. |
434 |
|
|
* We insert the new screen after the old one. If we're exiting, |
435 |
|
|
* the exit will delete the old one, if we're foregrounding, the fg |
436 |
|
|
* code will move the old one to the background queue. |
437 |
|
|
*/ |
438 |
|
|
TAILQ_REMOVE(&gp->hq, nsp, q); |
439 |
|
|
TAILQ_INSERT_AFTER(&gp->dq, sp, nsp, q); |
440 |
|
|
|
441 |
|
|
/* |
442 |
|
|
* Don't change the screen's cursor information other than to |
443 |
|
|
* note that the cursor is wrong. |
444 |
|
|
*/ |
445 |
|
|
F_SET(VIP(nsp), VIP_CUR_INVALID); |
446 |
|
|
|
447 |
|
|
/* Draw the new screen from scratch, and add a status line. */ |
448 |
|
|
F_SET(nsp, SC_SCR_REDRAW | SC_STATUS); |
449 |
|
|
return (0); |
450 |
|
|
} |
451 |
|
|
|
452 |
|
|
/* |
453 |
|
|
* vs_resize -- |
454 |
|
|
* Change the absolute size of the current screen. |
455 |
|
|
* |
456 |
|
|
* PUBLIC: int vs_resize(SCR *, long, adj_t); |
457 |
|
|
*/ |
458 |
|
|
int |
459 |
|
|
vs_resize(SCR *sp, long count, adj_t adj) |
460 |
|
|
{ |
461 |
|
|
GS *gp; |
462 |
|
|
SCR *g, *s; |
463 |
|
|
size_t g_off, s_off; |
464 |
|
|
|
465 |
|
|
gp = sp->gp; |
466 |
|
|
|
467 |
|
|
/* |
468 |
|
|
* Figure out which screens will grow, which will shrink, and |
469 |
|
|
* make sure it's possible. |
470 |
|
|
*/ |
471 |
|
|
if (count == 0) |
472 |
|
|
return (0); |
473 |
|
|
if (adj == A_SET) { |
474 |
|
|
if (sp->t_maxrows == count) |
475 |
|
|
return (0); |
476 |
|
|
if (sp->t_maxrows > count) { |
477 |
|
|
adj = A_DECREASE; |
478 |
|
|
count = sp->t_maxrows - count; |
479 |
|
|
} else { |
480 |
|
|
adj = A_INCREASE; |
481 |
|
|
count = count - sp->t_maxrows; |
482 |
|
|
} |
483 |
|
|
} |
484 |
|
|
|
485 |
|
|
g_off = s_off = 0; |
486 |
|
|
if (adj == A_DECREASE) { |
487 |
|
|
if (count < 0) |
488 |
|
|
count = -count; |
489 |
|
|
s = sp; |
490 |
|
|
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) |
491 |
|
|
goto toosmall; |
492 |
|
|
if ((g = TAILQ_PREV(sp, _dqh, q)) == NULL) { |
493 |
|
|
if ((g = TAILQ_NEXT(sp, q)) == NULL) |
494 |
|
|
goto toobig; |
495 |
|
|
g_off = -count; |
496 |
|
|
} else |
497 |
|
|
s_off = count; |
498 |
|
|
} else { |
499 |
|
|
g = sp; |
500 |
|
|
if ((s = TAILQ_NEXT(sp, q))) |
501 |
|
|
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) |
502 |
|
|
s = NULL; |
503 |
|
|
else |
504 |
|
|
s_off = count; |
505 |
|
|
else |
506 |
|
|
s = NULL; |
507 |
|
|
if (s == NULL) { |
508 |
|
|
if ((s = TAILQ_PREV(sp, _dqh, q)) == NULL) { |
509 |
|
|
toobig: msgq(sp, M_BERR, adj == A_DECREASE ? |
510 |
|
|
"The screen cannot shrink" : |
511 |
|
|
"The screen cannot grow"); |
512 |
|
|
return (1); |
513 |
|
|
} |
514 |
|
|
if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count) { |
515 |
|
|
toosmall: msgq(sp, M_BERR, |
516 |
|
|
"The screen can only shrink to %d rows", |
517 |
|
|
MINIMUM_SCREEN_ROWS); |
518 |
|
|
return (1); |
519 |
|
|
} |
520 |
|
|
g_off = -count; |
521 |
|
|
} |
522 |
|
|
} |
523 |
|
|
|
524 |
|
|
/* |
525 |
|
|
* Fix up the screens; we could optimize the reformatting of the |
526 |
|
|
* screen, but this isn't likely to be a common enough operation |
527 |
|
|
* to make it worthwhile. |
528 |
|
|
*/ |
529 |
|
|
s->rows += -count; |
530 |
|
|
s->woff += s_off; |
531 |
|
|
g->rows += count; |
532 |
|
|
g->woff += g_off; |
533 |
|
|
|
534 |
|
|
g->t_rows += count; |
535 |
|
|
if (g->t_minrows == g->t_maxrows) |
536 |
|
|
g->t_minrows += count; |
537 |
|
|
g->t_maxrows += count; |
538 |
|
|
_TMAP(g) += count; |
539 |
|
|
F_SET(g, SC_SCR_REFORMAT | SC_STATUS); |
540 |
|
|
|
541 |
|
|
s->t_rows -= count; |
542 |
|
|
s->t_maxrows -= count; |
543 |
|
|
if (s->t_minrows > s->t_maxrows) |
544 |
|
|
s->t_minrows = s->t_maxrows; |
545 |
|
|
_TMAP(s) -= count; |
546 |
|
|
F_SET(s, SC_SCR_REFORMAT | SC_STATUS); |
547 |
|
|
|
548 |
|
|
return (0); |
549 |
|
|
} |
550 |
|
|
|
551 |
|
|
/* |
552 |
|
|
* vs_getbg -- |
553 |
|
|
* Get the specified background screen, or, if name is NULL, the first |
554 |
|
|
* background screen. |
555 |
|
|
*/ |
556 |
|
|
static SCR * |
557 |
|
|
vs_getbg(SCR *sp, char *name) |
558 |
|
|
{ |
559 |
|
|
GS *gp; |
560 |
|
|
SCR *nsp; |
561 |
|
|
char *p; |
562 |
|
|
|
563 |
|
|
gp = sp->gp; |
564 |
|
|
|
565 |
|
|
/* If name is NULL, return the first background screen on the list. */ |
566 |
|
|
if (name == NULL) |
567 |
|
|
return (TAILQ_FIRST(&gp->hq)); |
568 |
|
|
|
569 |
|
|
/* Search for a full match. */ |
570 |
|
|
TAILQ_FOREACH(nsp, &gp->hq, q) { |
571 |
|
|
if (!strcmp(nsp->frp->name, name)) |
572 |
|
|
return(nsp); |
573 |
|
|
} |
574 |
|
|
|
575 |
|
|
/* Search for a last-component match. */ |
576 |
|
|
TAILQ_FOREACH(nsp, &gp->hq, q) { |
577 |
|
|
if ((p = strrchr(nsp->frp->name, '/')) == NULL) |
578 |
|
|
p = nsp->frp->name; |
579 |
|
|
else |
580 |
|
|
++p; |
581 |
|
|
if (!strcmp(p, name)) |
582 |
|
|
return(nsp); |
583 |
|
|
} |
584 |
|
|
|
585 |
|
|
return (NULL); |
586 |
|
|
} |