1*5b133f3fSguenther /* $OpenBSD: window.c,v 1.37 2023/03/08 04:43:11 guenther Exp $ */
200e5ac59Skjell
300e5ac59Skjell /* This file is in the public domain. */
4d4e7c603Sniklas
5be803e14Sderaadt /*
6be803e14Sderaadt * Window handling.
7be803e14Sderaadt */
88cad3a2cSmillert
9cc6738c5Sbcallah #include <sys/queue.h>
10cc6738c5Sbcallah #include <signal.h>
11cc6738c5Sbcallah #include <stdio.h>
12cc6738c5Sbcallah #include <stdlib.h>
13cc6738c5Sbcallah
14be803e14Sderaadt #include "def.h"
15be803e14Sderaadt
162818a53fSderaadt struct mgwin *
new_window(struct buffer * bp)172818a53fSderaadt new_window(struct buffer *bp)
18e3947453Svincent {
192818a53fSderaadt struct mgwin *wp;
20e3947453Svincent
212818a53fSderaadt wp = calloc(1, sizeof(struct mgwin));
22e3947453Svincent if (wp == NULL)
23e3947453Svincent return (NULL);
24e3947453Svincent
25e3947453Svincent wp->w_bufp = bp;
26e3947453Svincent wp->w_dotp = NULL;
27e3947453Svincent wp->w_doto = 0;
28e3947453Svincent wp->w_markp = NULL;
29e3947453Svincent wp->w_marko = 0;
30f14f890aSkjell wp->w_rflag = 0;
31b4fed989Skjell wp->w_frame = 0;
32dc9e748cSvincent wp->w_wrapline = NULL;
33b2f80e6eSkjell wp->w_dotline = wp->w_markline = 1;
34129bed2dSvincent if (bp)
35e3947453Svincent bp->b_nwnd++;
36e3947453Svincent return (wp);
37e3947453Svincent }
38e3947453Svincent
39be803e14Sderaadt /*
408cad3a2cSmillert * Reposition dot in the current window to line "n". If the argument is
418cad3a2cSmillert * positive, it is that line. If it is negative it is that line from the
428cad3a2cSmillert * bottom. If it is 0 the window is centered (this is what the standard
4399884f6bSbcallah * redisplay code does).
44be803e14Sderaadt */
458cad3a2cSmillert int
reposition(int f,int n)46444cb8bcScloder reposition(int f, int n)
47be803e14Sderaadt {
48b4fed989Skjell curwp->w_frame = (f & FFARG) ? (n >= 0 ? n + 1 : n) : 0;
49f14f890aSkjell curwp->w_rflag |= WFFRAME;
50be803e14Sderaadt sgarbf = TRUE;
51f66aba3dSdb return (TRUE);
52be803e14Sderaadt }
53be803e14Sderaadt
54be803e14Sderaadt /*
558cad3a2cSmillert * Refresh the display. A call is made to the "ttresize" entry in the
568cad3a2cSmillert * terminal handler, which tries to reset "nrow" and "ncol". They will,
578cad3a2cSmillert * however, never be set outside of the NROW or NCOL range. If the display
588cad3a2cSmillert * changed size, arrange that everything is redone, then call "update" to
598cad3a2cSmillert * fix the display. We do this so the new size can be displayed. In the
608cad3a2cSmillert * normal case the call to "update" in "main.c" refreshes the screen, and
61db74fa37Sotto * all of the windows need not be recomputed. This call includes a
62db74fa37Sotto * 'force' parameter to ensure that the redraw is done, even after a
63db74fa37Sotto * a suspend/continue (where the window size parameters will already
64db74fa37Sotto * be updated). Note that when you get to the "display unusable"
65db74fa37Sotto * message, the screen will be messed up. If you make the window bigger
66db74fa37Sotto * again, and send another command, everything will get fixed!
67be803e14Sderaadt */
688cad3a2cSmillert int
redraw(int f,int n)69b055d85aSkjell redraw(int f, int n)
70be803e14Sderaadt {
71db74fa37Sotto return (do_redraw(f, n, FALSE));
72db74fa37Sotto }
73db74fa37Sotto
74db74fa37Sotto int
do_redraw(int f,int n,int force)75db74fa37Sotto do_redraw(int f, int n, int force)
76db74fa37Sotto {
772818a53fSderaadt struct mgwin *wp;
782818a53fSderaadt int oldnrow, oldncol;
79be803e14Sderaadt
80be803e14Sderaadt oldnrow = nrow;
81be803e14Sderaadt oldncol = ncol;
82be803e14Sderaadt ttresize();
83db74fa37Sotto if (nrow != oldnrow || ncol != oldncol || force) {
848cad3a2cSmillert
858cad3a2cSmillert /* find last */
868cad3a2cSmillert wp = wheadp;
87be803e14Sderaadt while (wp->w_wndp != NULL)
88be803e14Sderaadt wp = wp->w_wndp;
898cad3a2cSmillert
908cad3a2cSmillert /* check if too small */
918cad3a2cSmillert if (nrow < wp->w_toprow + 3) {
92dbf27552Slum dobeep();
93be803e14Sderaadt ewprintf("Display unusable");
94be803e14Sderaadt return (FALSE);
95be803e14Sderaadt }
96be803e14Sderaadt wp->w_ntrows = nrow - wp->w_toprow - 2;
97be803e14Sderaadt sgarbf = TRUE;
98048419bbSlum update(CMODE);
99be803e14Sderaadt } else
100be803e14Sderaadt sgarbf = TRUE;
101f66aba3dSdb return (TRUE);
102be803e14Sderaadt }
103be803e14Sderaadt
104be803e14Sderaadt /*
1058cad3a2cSmillert * The command to make the next window (next => down the screen) the current
1068cad3a2cSmillert * window. There are no real errors, although the command does nothing if
1078cad3a2cSmillert * there is only 1 window on the screen.
108be803e14Sderaadt */
1098cad3a2cSmillert int
nextwind(int f,int n)110444cb8bcScloder nextwind(int f, int n)
111be803e14Sderaadt {
1122818a53fSderaadt struct mgwin *wp;
113be803e14Sderaadt
114be803e14Sderaadt if ((wp = curwp->w_wndp) == NULL)
115be803e14Sderaadt wp = wheadp;
116be803e14Sderaadt curwp = wp;
117be803e14Sderaadt curbp = wp->w_bufp;
118f66aba3dSdb return (TRUE);
119be803e14Sderaadt }
120be803e14Sderaadt
1215ef5b4beSlum /* not in GNU Emacs */
122be803e14Sderaadt /*
1238cad3a2cSmillert * This command makes the previous window (previous => up the screen) the
1248cad3a2cSmillert * current window. There are no errors, although the command does not do
1258cad3a2cSmillert * a lot if there is only 1 window.
126be803e14Sderaadt */
1278cad3a2cSmillert int
prevwind(int f,int n)128444cb8bcScloder prevwind(int f, int n)
129be803e14Sderaadt {
1302818a53fSderaadt struct mgwin *wp1, *wp2;
131be803e14Sderaadt
132be803e14Sderaadt wp1 = wheadp;
133be803e14Sderaadt wp2 = curwp;
134be803e14Sderaadt if (wp1 == wp2)
135be803e14Sderaadt wp2 = NULL;
136be803e14Sderaadt while (wp1->w_wndp != wp2)
137be803e14Sderaadt wp1 = wp1->w_wndp;
138be803e14Sderaadt curwp = wp1;
139be803e14Sderaadt curbp = wp1->w_bufp;
140f66aba3dSdb return (TRUE);
141be803e14Sderaadt }
142be803e14Sderaadt
143be803e14Sderaadt /*
1448cad3a2cSmillert * This command makes the current window the only window on the screen. Try
1458cad3a2cSmillert * to set the framing so that "." does not have to move on the display. Some
1468cad3a2cSmillert * care has to be taken to keep the values of dot and mark in the buffer
147f66aba3dSdb * structures right if the destruction of a window makes a buffer become
1488cad3a2cSmillert * undisplayed.
149be803e14Sderaadt */
1508cad3a2cSmillert int
onlywind(int f,int n)151444cb8bcScloder onlywind(int f, int n)
152be803e14Sderaadt {
1532818a53fSderaadt struct mgwin *wp;
1542818a53fSderaadt struct line *lp;
1558cad3a2cSmillert int i;
156be803e14Sderaadt
157be803e14Sderaadt while (wheadp != curwp) {
158be803e14Sderaadt wp = wheadp;
159be803e14Sderaadt wheadp = wp->w_wndp;
160be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) {
161be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp;
162be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto;
163be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp;
164be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko;
165e8a775f1Slum wp->w_bufp->b_dotline = wp->w_dotline;
166e8a775f1Slum wp->w_bufp->b_markline = wp->w_markline;
167be803e14Sderaadt }
168c51f3144Skjell free(wp);
169be803e14Sderaadt }
170be803e14Sderaadt while (curwp->w_wndp != NULL) {
171be803e14Sderaadt wp = curwp->w_wndp;
172be803e14Sderaadt curwp->w_wndp = wp->w_wndp;
173be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) {
174be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp;
175be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto;
176be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp;
177be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko;
178e8a775f1Slum wp->w_bufp->b_dotline = wp->w_dotline;
179e8a775f1Slum wp->w_bufp->b_markline = wp->w_markline;
180be803e14Sderaadt }
181c51f3144Skjell free(wp);
182be803e14Sderaadt }
183be803e14Sderaadt lp = curwp->w_linep;
184be803e14Sderaadt i = curwp->w_toprow;
185b669aed8Skjell while (i != 0 && lback(lp) != curbp->b_headp) {
186be803e14Sderaadt --i;
187be803e14Sderaadt lp = lback(lp);
188be803e14Sderaadt }
189be803e14Sderaadt curwp->w_toprow = 0;
1908cad3a2cSmillert
1918cad3a2cSmillert /* 2 = mode, echo */
1928cad3a2cSmillert curwp->w_ntrows = nrow - 2;
193be803e14Sderaadt curwp->w_linep = lp;
194f14f890aSkjell curwp->w_rflag |= WFMODE | WFFULL;
195f66aba3dSdb return (TRUE);
196be803e14Sderaadt }
197be803e14Sderaadt
198be803e14Sderaadt /*
1998cad3a2cSmillert * Split the current window. A window smaller than 3 lines cannot be split.
2008cad3a2cSmillert * The only other error that is possible is a "malloc" failure allocating the
2018cad3a2cSmillert * structure for the new window.
202d4718e25Skjell * If called with a FFOTHARG, flags on the new window are set to 'n'.
203be803e14Sderaadt */
2048cad3a2cSmillert int
splitwind(int f,int n)205444cb8bcScloder splitwind(int f, int n)
206be803e14Sderaadt {
2072818a53fSderaadt struct mgwin *wp, *wp1, *wp2;
2082818a53fSderaadt struct line *lp;
2098cad3a2cSmillert int ntru, ntrd, ntrl;
210be803e14Sderaadt
211be803e14Sderaadt if (curwp->w_ntrows < 3) {
212dbf27552Slum dobeep();
213be803e14Sderaadt ewprintf("Cannot split a %d line window", curwp->w_ntrows);
214be803e14Sderaadt return (FALSE);
215be803e14Sderaadt }
216e3947453Svincent wp = new_window(curbp);
217e3947453Svincent if (wp == NULL) {
218dbf27552Slum dobeep();
219e3947453Svincent ewprintf("Unable to create a window");
220be803e14Sderaadt return (FALSE);
221be803e14Sderaadt }
2228cad3a2cSmillert
223e3947453Svincent /* use the current dot and mark */
224be803e14Sderaadt wp->w_dotp = curwp->w_dotp;
225be803e14Sderaadt wp->w_doto = curwp->w_doto;
226be803e14Sderaadt wp->w_markp = curwp->w_markp;
227be803e14Sderaadt wp->w_marko = curwp->w_marko;
228b2f80e6eSkjell wp->w_dotline = curwp->w_dotline;
229b2f80e6eSkjell wp->w_markline = curwp->w_markline;
230e3947453Svincent
231e3947453Svincent /* figure out which half of the screen we're in */
232be803e14Sderaadt ntru = (curwp->w_ntrows - 1) / 2; /* Upper size */
233be803e14Sderaadt ntrl = (curwp->w_ntrows - 1) - ntru; /* Lower size */
234e3947453Svincent
235e3947453Svincent for (lp = curwp->w_linep, ntrd = 0; lp != curwp->w_dotp;
236e3947453Svincent lp = lforw(lp))
237e3947453Svincent ntrd++;
238e3947453Svincent
239be803e14Sderaadt lp = curwp->w_linep;
2408cad3a2cSmillert
2418cad3a2cSmillert /* old is upper window */
2428cad3a2cSmillert if (ntrd <= ntru) {
2438cad3a2cSmillert /* hit mode line */
2448cad3a2cSmillert if (ntrd == ntru)
245be803e14Sderaadt lp = lforw(lp);
246be803e14Sderaadt curwp->w_ntrows = ntru;
247be803e14Sderaadt wp->w_wndp = curwp->w_wndp;
248be803e14Sderaadt curwp->w_wndp = wp;
249be803e14Sderaadt wp->w_toprow = curwp->w_toprow + ntru + 1;
250be803e14Sderaadt wp->w_ntrows = ntrl;
2518cad3a2cSmillert /* old is lower window */
2528cad3a2cSmillert } else {
253be803e14Sderaadt wp1 = NULL;
254be803e14Sderaadt wp2 = wheadp;
255be803e14Sderaadt while (wp2 != curwp) {
256be803e14Sderaadt wp1 = wp2;
257be803e14Sderaadt wp2 = wp2->w_wndp;
258be803e14Sderaadt }
259be803e14Sderaadt if (wp1 == NULL)
260be803e14Sderaadt wheadp = wp;
261be803e14Sderaadt else
262be803e14Sderaadt wp1->w_wndp = wp;
263be803e14Sderaadt wp->w_wndp = curwp;
264be803e14Sderaadt wp->w_toprow = curwp->w_toprow;
265be803e14Sderaadt wp->w_ntrows = ntru;
2668cad3a2cSmillert
2678cad3a2cSmillert /* mode line */
2688cad3a2cSmillert ++ntru;
269be803e14Sderaadt curwp->w_toprow += ntru;
270be803e14Sderaadt curwp->w_ntrows = ntrl;
271be803e14Sderaadt while (ntru--)
272be803e14Sderaadt lp = lforw(lp);
273be803e14Sderaadt }
2748cad3a2cSmillert
2758cad3a2cSmillert /* adjust the top lines if necessary */
2768cad3a2cSmillert curwp->w_linep = lp;
2778cad3a2cSmillert wp->w_linep = lp;
2788cad3a2cSmillert
279f14f890aSkjell curwp->w_rflag |= WFMODE | WFFULL;
280f14f890aSkjell wp->w_rflag |= WFMODE | WFFULL;
281d4718e25Skjell /* if FFOTHARG, set flags) */
282d4718e25Skjell if (f & FFOTHARG)
283d4718e25Skjell wp->w_flag = n;
284d4718e25Skjell
285f66aba3dSdb return (TRUE);
286be803e14Sderaadt }
287be803e14Sderaadt
288be803e14Sderaadt /*
2898cad3a2cSmillert * Enlarge the current window. Find the window that loses space. Make sure
2908cad3a2cSmillert * it is big enough. If so, hack the window descriptions, and ask redisplay
2918cad3a2cSmillert * to do all the hard work. You don't just set "force reframe" because dot
2928cad3a2cSmillert * would move.
293be803e14Sderaadt */
2948cad3a2cSmillert int
enlargewind(int f,int n)295444cb8bcScloder enlargewind(int f, int n)
296be803e14Sderaadt {
2972818a53fSderaadt struct mgwin *adjwp;
2982818a53fSderaadt struct line *lp;
2998cad3a2cSmillert int i;
300be803e14Sderaadt
301be803e14Sderaadt if (n < 0)
302f66aba3dSdb return (shrinkwind(f, -n));
303be803e14Sderaadt if (wheadp->w_wndp == NULL) {
304dbf27552Slum dobeep();
305be803e14Sderaadt ewprintf("Only one window");
306f66aba3dSdb return (FALSE);
307be803e14Sderaadt }
308be803e14Sderaadt if ((adjwp = curwp->w_wndp) == NULL) {
309be803e14Sderaadt adjwp = wheadp;
310be803e14Sderaadt while (adjwp->w_wndp != curwp)
311be803e14Sderaadt adjwp = adjwp->w_wndp;
312be803e14Sderaadt }
313be803e14Sderaadt if (adjwp->w_ntrows <= n) {
314dbf27552Slum dobeep();
315be803e14Sderaadt ewprintf("Impossible change");
316f66aba3dSdb return (FALSE);
317be803e14Sderaadt }
3188cad3a2cSmillert
3198cad3a2cSmillert /* shrink below */
3208cad3a2cSmillert if (curwp->w_wndp == adjwp) {
321be803e14Sderaadt lp = adjwp->w_linep;
322b669aed8Skjell for (i = 0; i < n && lp != adjwp->w_bufp->b_headp; ++i)
323be803e14Sderaadt lp = lforw(lp);
324be803e14Sderaadt adjwp->w_linep = lp;
325be803e14Sderaadt adjwp->w_toprow += n;
3268cad3a2cSmillert /* shrink above */
3278cad3a2cSmillert } else {
328be803e14Sderaadt lp = curwp->w_linep;
329b669aed8Skjell for (i = 0; i < n && lback(lp) != curbp->b_headp; ++i)
330be803e14Sderaadt lp = lback(lp);
331be803e14Sderaadt curwp->w_linep = lp;
332be803e14Sderaadt curwp->w_toprow -= n;
333be803e14Sderaadt }
334be803e14Sderaadt curwp->w_ntrows += n;
335be803e14Sderaadt adjwp->w_ntrows -= n;
336f14f890aSkjell curwp->w_rflag |= WFMODE | WFFULL;
337f14f890aSkjell adjwp->w_rflag |= WFMODE | WFFULL;
338f66aba3dSdb return (TRUE);
339be803e14Sderaadt }
340be803e14Sderaadt
341be803e14Sderaadt /*
3428cad3a2cSmillert * Shrink the current window. Find the window that gains space. Hack at the
3438cad3a2cSmillert * window descriptions. Ask the redisplay to do all the hard work.
344be803e14Sderaadt */
3458cad3a2cSmillert int
shrinkwind(int f,int n)346444cb8bcScloder shrinkwind(int f, int n)
347be803e14Sderaadt {
3482818a53fSderaadt struct mgwin *adjwp;
3492818a53fSderaadt struct line *lp;
3508cad3a2cSmillert int i;
351be803e14Sderaadt
352be803e14Sderaadt if (n < 0)
353f66aba3dSdb return (enlargewind(f, -n));
354be803e14Sderaadt if (wheadp->w_wndp == NULL) {
355dbf27552Slum dobeep();
356be803e14Sderaadt ewprintf("Only one window");
357f66aba3dSdb return (FALSE);
358be803e14Sderaadt }
359be803e14Sderaadt /*
360b1bfa5b4Slum * Bit of flakiness - FFRAND means it was an internal call, and
361be803e14Sderaadt * to be trusted implicitly about sizes.
362be803e14Sderaadt */
363be803e14Sderaadt if (!(f & FFRAND) && curwp->w_ntrows <= n) {
364dbf27552Slum dobeep();
365be803e14Sderaadt ewprintf("Impossible change");
366be803e14Sderaadt return (FALSE);
367be803e14Sderaadt }
368be803e14Sderaadt if ((adjwp = curwp->w_wndp) == NULL) {
369be803e14Sderaadt adjwp = wheadp;
370be803e14Sderaadt while (adjwp->w_wndp != curwp)
371be803e14Sderaadt adjwp = adjwp->w_wndp;
372be803e14Sderaadt }
3738cad3a2cSmillert
3748cad3a2cSmillert /* grow below */
3758cad3a2cSmillert if (curwp->w_wndp == adjwp) {
376be803e14Sderaadt lp = adjwp->w_linep;
377b669aed8Skjell for (i = 0; i < n && lback(lp) != adjwp->w_bufp->b_headp; ++i)
378be803e14Sderaadt lp = lback(lp);
379be803e14Sderaadt adjwp->w_linep = lp;
380be803e14Sderaadt adjwp->w_toprow -= n;
3818cad3a2cSmillert /* grow above */
3828cad3a2cSmillert } else {
383be803e14Sderaadt lp = curwp->w_linep;
384b669aed8Skjell for (i = 0; i < n && lp != curbp->b_headp; ++i)
385be803e14Sderaadt lp = lforw(lp);
386be803e14Sderaadt curwp->w_linep = lp;
387be803e14Sderaadt curwp->w_toprow += n;
388be803e14Sderaadt }
389be803e14Sderaadt curwp->w_ntrows -= n;
390be803e14Sderaadt adjwp->w_ntrows += n;
391f14f890aSkjell curwp->w_rflag |= WFMODE | WFFULL;
392f14f890aSkjell adjwp->w_rflag |= WFMODE | WFFULL;
393be803e14Sderaadt return (TRUE);
394be803e14Sderaadt }
395be803e14Sderaadt
396be803e14Sderaadt /*
3978cad3a2cSmillert * Delete current window. Call shrink-window to do the screen updating, then
3988cad3a2cSmillert * throw away the window.
399be803e14Sderaadt */
4008cad3a2cSmillert int
delwind(int f,int n)401444cb8bcScloder delwind(int f, int n)
402be803e14Sderaadt {
4032818a53fSderaadt struct mgwin *wp, *nwp;
404be803e14Sderaadt
405be803e14Sderaadt wp = curwp; /* Cheap... */
4068cad3a2cSmillert
407be803e14Sderaadt /* shrinkwind returning false means only one window... */
408be803e14Sderaadt if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE)
409f66aba3dSdb return (FALSE);
410be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) {
411be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp;
412be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto;
413be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp;
414be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko;
415b493fd45Sflorian wp->w_bufp->b_dotline = wp->w_dotline;
416b493fd45Sflorian wp->w_bufp->b_markline = wp->w_markline;
417be803e14Sderaadt }
4188cad3a2cSmillert
419be803e14Sderaadt /* since shrinkwind did't crap out, we know we have a second window */
420371f5030Smillert if (wp == wheadp)
421371f5030Smillert wheadp = curwp = wp->w_wndp;
422371f5030Smillert else if ((curwp = wp->w_wndp) == NULL)
423371f5030Smillert curwp = wheadp;
424be803e14Sderaadt curbp = curwp->w_bufp;
425be803e14Sderaadt for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp)
426be803e14Sderaadt if (nwp->w_wndp == wp) {
427be803e14Sderaadt nwp->w_wndp = wp->w_wndp;
428be803e14Sderaadt break;
429be803e14Sderaadt }
430c51f3144Skjell free(wp);
431f66aba3dSdb return (TRUE);
432be803e14Sderaadt }
433