1*b4fed989Skjell /* $OpenBSD: window.c,v 1.23 2006/05/29 00:02:23 kjell Exp $ */ 200e5ac59Skjell 300e5ac59Skjell /* This file is in the public domain. */ 4d4e7c603Sniklas 5be803e14Sderaadt /* 6be803e14Sderaadt * Window handling. 7be803e14Sderaadt */ 88cad3a2cSmillert 9be803e14Sderaadt #include "def.h" 10be803e14Sderaadt 112818a53fSderaadt struct mgwin * 122818a53fSderaadt new_window(struct buffer *bp) 13e3947453Svincent { 142818a53fSderaadt struct mgwin *wp; 15e3947453Svincent 162818a53fSderaadt wp = calloc(1, sizeof(struct mgwin)); 17e3947453Svincent if (wp == NULL) 18e3947453Svincent return (NULL); 19e3947453Svincent 20e3947453Svincent wp->w_bufp = bp; 21e3947453Svincent wp->w_dotp = NULL; 22e3947453Svincent wp->w_doto = 0; 23e3947453Svincent wp->w_markp = NULL; 24e3947453Svincent wp->w_marko = 0; 25e3947453Svincent wp->w_flag = 0; 26*b4fed989Skjell wp->w_frame = 0; 27dc9e748cSvincent wp->w_wrapline = NULL; 28129bed2dSvincent if (bp) 29e3947453Svincent bp->b_nwnd++; 30e3947453Svincent return (wp); 31e3947453Svincent } 32e3947453Svincent 33be803e14Sderaadt /* 348cad3a2cSmillert * Reposition dot in the current window to line "n". If the argument is 358cad3a2cSmillert * positive, it is that line. If it is negative it is that line from the 368cad3a2cSmillert * bottom. If it is 0 the window is centered (this is what the standard 378cad3a2cSmillert * redisplay code does). If GOSREC is undefined, default is 0, so it acts 388cad3a2cSmillert * like GNU. If GOSREC is defined, with no argument it defaults to 1 and 398cad3a2cSmillert * works like in Gosling. 40be803e14Sderaadt */ 41be803e14Sderaadt /* ARGSUSED */ 428cad3a2cSmillert int 43444cb8bcScloder reposition(int f, int n) 44be803e14Sderaadt { 45be803e14Sderaadt #ifndef GOSREC 46*b4fed989Skjell curwp->w_frame = (f & FFARG) ? (n >= 0 ? n + 1 : n) : 0; 478cad3a2cSmillert #else /* !GOSREC */ 48*b4fed989Skjell curwp->w_frame = n; 498cad3a2cSmillert #endif /* !GOSREC */ 50d1db3928Skjell curwp->w_flag |= WFFRAME; 51be803e14Sderaadt sgarbf = TRUE; 52f66aba3dSdb return (TRUE); 53be803e14Sderaadt } 54be803e14Sderaadt 55be803e14Sderaadt /* 568cad3a2cSmillert * Refresh the display. A call is made to the "ttresize" entry in the 578cad3a2cSmillert * terminal handler, which tries to reset "nrow" and "ncol". They will, 588cad3a2cSmillert * however, never be set outside of the NROW or NCOL range. If the display 598cad3a2cSmillert * changed size, arrange that everything is redone, then call "update" to 608cad3a2cSmillert * fix the display. We do this so the new size can be displayed. In the 618cad3a2cSmillert * normal case the call to "update" in "main.c" refreshes the screen, and 62db74fa37Sotto * all of the windows need not be recomputed. This call includes a 63db74fa37Sotto * 'force' parameter to ensure that the redraw is done, even after a 64db74fa37Sotto * a suspend/continue (where the window size parameters will already 65db74fa37Sotto * be updated). Note that when you get to the "display unusable" 66db74fa37Sotto * message, the screen will be messed up. If you make the window bigger 67db74fa37Sotto * again, and send another command, everything will get fixed! 68be803e14Sderaadt */ 698cad3a2cSmillert int 70b055d85aSkjell redraw(int f, int n) 71be803e14Sderaadt { 72db74fa37Sotto return (do_redraw(f, n, FALSE)); 73db74fa37Sotto } 74db74fa37Sotto 75db74fa37Sotto /* ARGSUSED */ 76db74fa37Sotto int 77db74fa37Sotto do_redraw(int f, int n, int force) 78db74fa37Sotto { 792818a53fSderaadt struct mgwin *wp; 802818a53fSderaadt int oldnrow, oldncol; 81be803e14Sderaadt 82be803e14Sderaadt oldnrow = nrow; 83be803e14Sderaadt oldncol = ncol; 84be803e14Sderaadt ttresize(); 85db74fa37Sotto if (nrow != oldnrow || ncol != oldncol || force) { 868cad3a2cSmillert 878cad3a2cSmillert /* find last */ 888cad3a2cSmillert wp = wheadp; 89be803e14Sderaadt while (wp->w_wndp != NULL) 90be803e14Sderaadt wp = wp->w_wndp; 918cad3a2cSmillert 928cad3a2cSmillert /* check if too small */ 938cad3a2cSmillert if (nrow < wp->w_toprow + 3) { 94be803e14Sderaadt ewprintf("Display unusable"); 95be803e14Sderaadt return (FALSE); 96be803e14Sderaadt } 97be803e14Sderaadt wp->w_ntrows = nrow - wp->w_toprow - 2; 98be803e14Sderaadt sgarbf = TRUE; 99be803e14Sderaadt update(); 100be803e14Sderaadt } else 101be803e14Sderaadt sgarbf = TRUE; 102f66aba3dSdb return (TRUE); 103be803e14Sderaadt } 104be803e14Sderaadt 105be803e14Sderaadt /* 1068cad3a2cSmillert * The command to make the next window (next => down the screen) the current 1078cad3a2cSmillert * window. There are no real errors, although the command does nothing if 1088cad3a2cSmillert * there is only 1 window on the screen. 109be803e14Sderaadt */ 110be803e14Sderaadt /* ARGSUSED */ 1118cad3a2cSmillert int 112444cb8bcScloder nextwind(int f, int n) 113be803e14Sderaadt { 1142818a53fSderaadt struct mgwin *wp; 115be803e14Sderaadt 116be803e14Sderaadt if ((wp = curwp->w_wndp) == NULL) 117be803e14Sderaadt wp = wheadp; 118be803e14Sderaadt curwp = wp; 119be803e14Sderaadt curbp = wp->w_bufp; 120f66aba3dSdb return (TRUE); 121be803e14Sderaadt } 122be803e14Sderaadt 123be803e14Sderaadt /* not in Gnu Emacs */ 124be803e14Sderaadt /* 1258cad3a2cSmillert * This command makes the previous window (previous => up the screen) the 1268cad3a2cSmillert * current window. There are no errors, although the command does not do 1278cad3a2cSmillert * a lot if there is only 1 window. 128be803e14Sderaadt */ 129be803e14Sderaadt /* ARGSUSED */ 1308cad3a2cSmillert int 131444cb8bcScloder prevwind(int f, int n) 132be803e14Sderaadt { 1332818a53fSderaadt struct mgwin *wp1, *wp2; 134be803e14Sderaadt 135be803e14Sderaadt wp1 = wheadp; 136be803e14Sderaadt wp2 = curwp; 137be803e14Sderaadt if (wp1 == wp2) 138be803e14Sderaadt wp2 = NULL; 139be803e14Sderaadt while (wp1->w_wndp != wp2) 140be803e14Sderaadt wp1 = wp1->w_wndp; 141be803e14Sderaadt curwp = wp1; 142be803e14Sderaadt curbp = wp1->w_bufp; 143f66aba3dSdb return (TRUE); 144be803e14Sderaadt } 145be803e14Sderaadt 146be803e14Sderaadt /* 1478cad3a2cSmillert * This command makes the current window the only window on the screen. Try 1488cad3a2cSmillert * to set the framing so that "." does not have to move on the display. Some 1498cad3a2cSmillert * care has to be taken to keep the values of dot and mark in the buffer 150f66aba3dSdb * structures right if the destruction of a window makes a buffer become 1518cad3a2cSmillert * undisplayed. 152be803e14Sderaadt */ 153be803e14Sderaadt /* ARGSUSED */ 1548cad3a2cSmillert int 155444cb8bcScloder onlywind(int f, int n) 156be803e14Sderaadt { 1572818a53fSderaadt struct mgwin *wp; 1582818a53fSderaadt struct line *lp; 1598cad3a2cSmillert int i; 160be803e14Sderaadt 161be803e14Sderaadt while (wheadp != curwp) { 162be803e14Sderaadt wp = wheadp; 163be803e14Sderaadt wheadp = wp->w_wndp; 164be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) { 165be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp; 166be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto; 167be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp; 168be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko; 169be803e14Sderaadt } 170c51f3144Skjell free(wp); 171be803e14Sderaadt } 172be803e14Sderaadt while (curwp->w_wndp != NULL) { 173be803e14Sderaadt wp = curwp->w_wndp; 174be803e14Sderaadt curwp->w_wndp = wp->w_wndp; 175be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) { 176be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp; 177be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto; 178be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp; 179be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko; 180be803e14Sderaadt } 181c51f3144Skjell free(wp); 182be803e14Sderaadt } 183be803e14Sderaadt lp = curwp->w_linep; 184be803e14Sderaadt i = curwp->w_toprow; 185be803e14Sderaadt while (i != 0 && lback(lp) != curbp->b_linep) { 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; 194d1db3928Skjell curwp->w_flag |= 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. 202be803e14Sderaadt */ 203be803e14Sderaadt /* ARGSUSED */ 2048cad3a2cSmillert int 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) { 212be803e14Sderaadt ewprintf("Cannot split a %d line window", curwp->w_ntrows); 213be803e14Sderaadt return (FALSE); 214be803e14Sderaadt } 215e3947453Svincent wp = new_window(curbp); 216e3947453Svincent if (wp == NULL) { 217e3947453Svincent ewprintf("Unable to create a window"); 218be803e14Sderaadt return (FALSE); 219be803e14Sderaadt } 2208cad3a2cSmillert 221e3947453Svincent /* use the current dot and mark */ 222be803e14Sderaadt wp->w_dotp = curwp->w_dotp; 223be803e14Sderaadt wp->w_doto = curwp->w_doto; 224be803e14Sderaadt wp->w_markp = curwp->w_markp; 225be803e14Sderaadt wp->w_marko = curwp->w_marko; 226e3947453Svincent 227e3947453Svincent /* figure out which half of the screen we're in */ 228be803e14Sderaadt ntru = (curwp->w_ntrows - 1) / 2; /* Upper size */ 229be803e14Sderaadt ntrl = (curwp->w_ntrows - 1) - ntru; /* Lower size */ 230e3947453Svincent 231e3947453Svincent for (lp = curwp->w_linep, ntrd = 0; lp != curwp->w_dotp; 232e3947453Svincent lp = lforw(lp)) 233e3947453Svincent ntrd++; 234e3947453Svincent 235be803e14Sderaadt lp = curwp->w_linep; 2368cad3a2cSmillert 2378cad3a2cSmillert /* old is upper window */ 2388cad3a2cSmillert if (ntrd <= ntru) { 2398cad3a2cSmillert /* hit mode line */ 2408cad3a2cSmillert if (ntrd == ntru) 241be803e14Sderaadt lp = lforw(lp); 242be803e14Sderaadt curwp->w_ntrows = ntru; 243be803e14Sderaadt wp->w_wndp = curwp->w_wndp; 244be803e14Sderaadt curwp->w_wndp = wp; 245be803e14Sderaadt wp->w_toprow = curwp->w_toprow + ntru + 1; 246be803e14Sderaadt wp->w_ntrows = ntrl; 2478cad3a2cSmillert /* old is lower window */ 2488cad3a2cSmillert } else { 249be803e14Sderaadt wp1 = NULL; 250be803e14Sderaadt wp2 = wheadp; 251be803e14Sderaadt while (wp2 != curwp) { 252be803e14Sderaadt wp1 = wp2; 253be803e14Sderaadt wp2 = wp2->w_wndp; 254be803e14Sderaadt } 255be803e14Sderaadt if (wp1 == NULL) 256be803e14Sderaadt wheadp = wp; 257be803e14Sderaadt else 258be803e14Sderaadt wp1->w_wndp = wp; 259be803e14Sderaadt wp->w_wndp = curwp; 260be803e14Sderaadt wp->w_toprow = curwp->w_toprow; 261be803e14Sderaadt wp->w_ntrows = ntru; 2628cad3a2cSmillert 2638cad3a2cSmillert /* mode line */ 2648cad3a2cSmillert ++ntru; 265be803e14Sderaadt curwp->w_toprow += ntru; 266be803e14Sderaadt curwp->w_ntrows = ntrl; 267be803e14Sderaadt while (ntru--) 268be803e14Sderaadt lp = lforw(lp); 269be803e14Sderaadt } 2708cad3a2cSmillert 2718cad3a2cSmillert /* adjust the top lines if necessary */ 2728cad3a2cSmillert curwp->w_linep = lp; 2738cad3a2cSmillert wp->w_linep = lp; 2748cad3a2cSmillert 275d1db3928Skjell curwp->w_flag |= WFMODE | WFFULL; 276d1db3928Skjell wp->w_flag |= WFMODE | WFFULL; 277f66aba3dSdb return (TRUE); 278be803e14Sderaadt } 279be803e14Sderaadt 280be803e14Sderaadt /* 2818cad3a2cSmillert * Enlarge the current window. Find the window that loses space. Make sure 2828cad3a2cSmillert * it is big enough. If so, hack the window descriptions, and ask redisplay 2838cad3a2cSmillert * to do all the hard work. You don't just set "force reframe" because dot 2848cad3a2cSmillert * would move. 285be803e14Sderaadt */ 286be803e14Sderaadt /* ARGSUSED */ 2878cad3a2cSmillert int 288444cb8bcScloder enlargewind(int f, int n) 289be803e14Sderaadt { 2902818a53fSderaadt struct mgwin *adjwp; 2912818a53fSderaadt struct line *lp; 2928cad3a2cSmillert int i; 293be803e14Sderaadt 294be803e14Sderaadt if (n < 0) 295f66aba3dSdb return (shrinkwind(f, -n)); 296be803e14Sderaadt if (wheadp->w_wndp == NULL) { 297be803e14Sderaadt ewprintf("Only one window"); 298f66aba3dSdb return (FALSE); 299be803e14Sderaadt } 300be803e14Sderaadt if ((adjwp = curwp->w_wndp) == NULL) { 301be803e14Sderaadt adjwp = wheadp; 302be803e14Sderaadt while (adjwp->w_wndp != curwp) 303be803e14Sderaadt adjwp = adjwp->w_wndp; 304be803e14Sderaadt } 305be803e14Sderaadt if (adjwp->w_ntrows <= n) { 306be803e14Sderaadt ewprintf("Impossible change"); 307f66aba3dSdb return (FALSE); 308be803e14Sderaadt } 3098cad3a2cSmillert 3108cad3a2cSmillert /* shrink below */ 3118cad3a2cSmillert if (curwp->w_wndp == adjwp) { 312be803e14Sderaadt lp = adjwp->w_linep; 313be803e14Sderaadt for (i = 0; i < n && lp != adjwp->w_bufp->b_linep; ++i) 314be803e14Sderaadt lp = lforw(lp); 315be803e14Sderaadt adjwp->w_linep = lp; 316be803e14Sderaadt adjwp->w_toprow += n; 3178cad3a2cSmillert /* shrink above */ 3188cad3a2cSmillert } else { 319be803e14Sderaadt lp = curwp->w_linep; 320be803e14Sderaadt for (i = 0; i < n && lback(lp) != curbp->b_linep; ++i) 321be803e14Sderaadt lp = lback(lp); 322be803e14Sderaadt curwp->w_linep = lp; 323be803e14Sderaadt curwp->w_toprow -= n; 324be803e14Sderaadt } 325be803e14Sderaadt curwp->w_ntrows += n; 326be803e14Sderaadt adjwp->w_ntrows -= n; 327d1db3928Skjell curwp->w_flag |= WFMODE | WFFULL; 328d1db3928Skjell adjwp->w_flag |= WFMODE | WFFULL; 329f66aba3dSdb return (TRUE); 330be803e14Sderaadt } 331be803e14Sderaadt 332be803e14Sderaadt /* 3338cad3a2cSmillert * Shrink the current window. Find the window that gains space. Hack at the 3348cad3a2cSmillert * window descriptions. Ask the redisplay to do all the hard work. 335be803e14Sderaadt */ 3368cad3a2cSmillert int 337444cb8bcScloder shrinkwind(int f, int n) 338be803e14Sderaadt { 3392818a53fSderaadt struct mgwin *adjwp; 3402818a53fSderaadt struct line *lp; 3418cad3a2cSmillert int i; 342be803e14Sderaadt 343be803e14Sderaadt if (n < 0) 344f66aba3dSdb return (enlargewind(f, -n)); 345be803e14Sderaadt if (wheadp->w_wndp == NULL) { 346be803e14Sderaadt ewprintf("Only one window"); 347f66aba3dSdb return (FALSE); 348be803e14Sderaadt } 349be803e14Sderaadt /* 350be803e14Sderaadt * Bit of flakiness - KRANDOM means it was an internal call, and 351be803e14Sderaadt * to be trusted implicitly about sizes. 352be803e14Sderaadt */ 353be803e14Sderaadt if (!(f & FFRAND) && curwp->w_ntrows <= n) { 354be803e14Sderaadt ewprintf("Impossible change"); 355be803e14Sderaadt return (FALSE); 356be803e14Sderaadt } 357be803e14Sderaadt if ((adjwp = curwp->w_wndp) == NULL) { 358be803e14Sderaadt adjwp = wheadp; 359be803e14Sderaadt while (adjwp->w_wndp != curwp) 360be803e14Sderaadt adjwp = adjwp->w_wndp; 361be803e14Sderaadt } 3628cad3a2cSmillert 3638cad3a2cSmillert /* grow below */ 3648cad3a2cSmillert if (curwp->w_wndp == adjwp) { 365be803e14Sderaadt lp = adjwp->w_linep; 366be803e14Sderaadt for (i = 0; i < n && lback(lp) != adjwp->w_bufp->b_linep; ++i) 367be803e14Sderaadt lp = lback(lp); 368be803e14Sderaadt adjwp->w_linep = lp; 369be803e14Sderaadt adjwp->w_toprow -= n; 3708cad3a2cSmillert /* grow above */ 3718cad3a2cSmillert } else { 372be803e14Sderaadt lp = curwp->w_linep; 373be803e14Sderaadt for (i = 0; i < n && lp != curbp->b_linep; ++i) 374be803e14Sderaadt lp = lforw(lp); 375be803e14Sderaadt curwp->w_linep = lp; 376be803e14Sderaadt curwp->w_toprow += n; 377be803e14Sderaadt } 378be803e14Sderaadt curwp->w_ntrows -= n; 379be803e14Sderaadt adjwp->w_ntrows += n; 380d1db3928Skjell curwp->w_flag |= WFMODE | WFFULL; 381d1db3928Skjell adjwp->w_flag |= WFMODE | WFFULL; 382be803e14Sderaadt return (TRUE); 383be803e14Sderaadt } 384be803e14Sderaadt 385be803e14Sderaadt /* 3868cad3a2cSmillert * Delete current window. Call shrink-window to do the screen updating, then 3878cad3a2cSmillert * throw away the window. 388be803e14Sderaadt */ 389be803e14Sderaadt /* ARGSUSED */ 3908cad3a2cSmillert int 391444cb8bcScloder delwind(int f, int n) 392be803e14Sderaadt { 3932818a53fSderaadt struct mgwin *wp, *nwp; 394be803e14Sderaadt 395be803e14Sderaadt wp = curwp; /* Cheap... */ 3968cad3a2cSmillert 397be803e14Sderaadt /* shrinkwind returning false means only one window... */ 398be803e14Sderaadt if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE) 399f66aba3dSdb return (FALSE); 400be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) { 401be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp; 402be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto; 403be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp; 404be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko; 405be803e14Sderaadt } 4068cad3a2cSmillert 407be803e14Sderaadt /* since shrinkwind did't crap out, we know we have a second window */ 408371f5030Smillert if (wp == wheadp) 409371f5030Smillert wheadp = curwp = wp->w_wndp; 410371f5030Smillert else if ((curwp = wp->w_wndp) == NULL) 411371f5030Smillert curwp = wheadp; 412be803e14Sderaadt curbp = curwp->w_bufp; 413be803e14Sderaadt for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp) 414be803e14Sderaadt if (nwp->w_wndp == wp) { 415be803e14Sderaadt nwp->w_wndp = wp->w_wndp; 416be803e14Sderaadt break; 417be803e14Sderaadt } 418c51f3144Skjell free(wp); 419f66aba3dSdb return (TRUE); 420be803e14Sderaadt } 4218cad3a2cSmillert 422be803e14Sderaadt /* 4238cad3a2cSmillert * Pick a window for a pop-up. Split the screen if there is only one window. 4248cad3a2cSmillert * Pick the uppermost window that isn't the current window. An LRU algorithm 4258cad3a2cSmillert * might be better. Return a pointer, or NULL on error. 426be803e14Sderaadt */ 4272818a53fSderaadt struct mgwin * 428444cb8bcScloder wpopup(void) 429371f5030Smillert { 4302818a53fSderaadt struct mgwin *wp; 431be803e14Sderaadt 4328b29b1f7Sderaadt if (wheadp->w_wndp == NULL && 4338b29b1f7Sderaadt splitwind(FFRAND, 0) == FALSE) 434f66aba3dSdb return (NULL); 4358cad3a2cSmillert 4368cad3a2cSmillert /* find a window to use */ 4378cad3a2cSmillert wp = wheadp; 4388cad3a2cSmillert 439be803e14Sderaadt while (wp != NULL && wp == curwp) 440be803e14Sderaadt wp = wp->w_wndp; 441f66aba3dSdb return (wp); 442be803e14Sderaadt } 443