1*444cb8bcScloder /* $OpenBSD: window.c,v 1.11 2003/05/20 03:08:55 cloder Exp $ */ 2d4e7c603Sniklas 3be803e14Sderaadt /* 4be803e14Sderaadt * Window handling. 5be803e14Sderaadt */ 68cad3a2cSmillert 7be803e14Sderaadt #include "def.h" 8be803e14Sderaadt 9be803e14Sderaadt /* 108cad3a2cSmillert * Reposition dot in the current window to line "n". If the argument is 118cad3a2cSmillert * positive, it is that line. If it is negative it is that line from the 128cad3a2cSmillert * bottom. If it is 0 the window is centered (this is what the standard 138cad3a2cSmillert * redisplay code does). If GOSREC is undefined, default is 0, so it acts 148cad3a2cSmillert * like GNU. If GOSREC is defined, with no argument it defaults to 1 and 158cad3a2cSmillert * works like in Gosling. 16be803e14Sderaadt */ 17be803e14Sderaadt /* ARGSUSED */ 188cad3a2cSmillert int 19*444cb8bcScloder reposition(int f, int n) 20be803e14Sderaadt { 21be803e14Sderaadt #ifndef GOSREC 22be803e14Sderaadt curwp->w_force = (f & FFARG) ? (n >= 0 ? n + 1 : n) : 0; 238cad3a2cSmillert #else /* !GOSREC */ 24be803e14Sderaadt curwp->w_force = n; 258cad3a2cSmillert #endif /* !GOSREC */ 26be803e14Sderaadt curwp->w_flag |= WFFORCE; 27be803e14Sderaadt sgarbf = TRUE; 28be803e14Sderaadt return TRUE; 29be803e14Sderaadt } 30be803e14Sderaadt 31be803e14Sderaadt /* 328cad3a2cSmillert * Refresh the display. A call is made to the "ttresize" entry in the 338cad3a2cSmillert * terminal handler, which tries to reset "nrow" and "ncol". They will, 348cad3a2cSmillert * however, never be set outside of the NROW or NCOL range. If the display 358cad3a2cSmillert * changed size, arrange that everything is redone, then call "update" to 368cad3a2cSmillert * fix the display. We do this so the new size can be displayed. In the 378cad3a2cSmillert * normal case the call to "update" in "main.c" refreshes the screen, and 388cad3a2cSmillert * all of the windows need not be recomputed. Note that when you get to the 398cad3a2cSmillert * "display unusable" message, the screen will be messed up. If you make the 408cad3a2cSmillert * window bigger again, and send another command, everything will get fixed! 41be803e14Sderaadt */ 42be803e14Sderaadt /* ARGSUSED */ 438cad3a2cSmillert int 44*444cb8bcScloder refresh(int f, int n) 45be803e14Sderaadt { 468cad3a2cSmillert MGWIN *wp; 478cad3a2cSmillert int oldnrow; 488cad3a2cSmillert int oldncol; 49be803e14Sderaadt 50be803e14Sderaadt oldnrow = nrow; 51be803e14Sderaadt oldncol = ncol; 52be803e14Sderaadt ttresize(); 53be803e14Sderaadt if (nrow != oldnrow || ncol != oldncol) { 548cad3a2cSmillert 558cad3a2cSmillert /* find last */ 568cad3a2cSmillert wp = wheadp; 57be803e14Sderaadt while (wp->w_wndp != NULL) 58be803e14Sderaadt wp = wp->w_wndp; 598cad3a2cSmillert 608cad3a2cSmillert /* check if too small */ 618cad3a2cSmillert if (nrow < wp->w_toprow + 3) { 62be803e14Sderaadt ewprintf("Display unusable"); 63be803e14Sderaadt return (FALSE); 64be803e14Sderaadt } 65be803e14Sderaadt wp->w_ntrows = nrow - wp->w_toprow - 2; 66be803e14Sderaadt sgarbf = TRUE; 67be803e14Sderaadt update(); 68be803e14Sderaadt } else 69be803e14Sderaadt sgarbf = TRUE; 70be803e14Sderaadt return TRUE; 71be803e14Sderaadt } 72be803e14Sderaadt 73be803e14Sderaadt /* 748cad3a2cSmillert * The command to make the next window (next => down the screen) the current 758cad3a2cSmillert * window. There are no real errors, although the command does nothing if 768cad3a2cSmillert * there is only 1 window on the screen. 77be803e14Sderaadt */ 78be803e14Sderaadt /* ARGSUSED */ 798cad3a2cSmillert int 80*444cb8bcScloder nextwind(int f, int n) 81be803e14Sderaadt { 828cad3a2cSmillert MGWIN *wp; 83be803e14Sderaadt 84be803e14Sderaadt if ((wp = curwp->w_wndp) == NULL) 85be803e14Sderaadt wp = wheadp; 86be803e14Sderaadt curwp = wp; 87be803e14Sderaadt curbp = wp->w_bufp; 88be803e14Sderaadt return TRUE; 89be803e14Sderaadt } 90be803e14Sderaadt 91be803e14Sderaadt /* not in Gnu Emacs */ 92be803e14Sderaadt /* 938cad3a2cSmillert * This command makes the previous window (previous => up the screen) the 948cad3a2cSmillert * current window. There are no errors, although the command does not do 958cad3a2cSmillert * a lot if there is only 1 window. 96be803e14Sderaadt */ 97be803e14Sderaadt /* ARGSUSED */ 988cad3a2cSmillert int 99*444cb8bcScloder prevwind(int f, int n) 100be803e14Sderaadt { 1018cad3a2cSmillert MGWIN *wp1, *wp2; 102be803e14Sderaadt 103be803e14Sderaadt wp1 = wheadp; 104be803e14Sderaadt wp2 = curwp; 105be803e14Sderaadt if (wp1 == wp2) 106be803e14Sderaadt wp2 = NULL; 107be803e14Sderaadt while (wp1->w_wndp != wp2) 108be803e14Sderaadt wp1 = wp1->w_wndp; 109be803e14Sderaadt curwp = wp1; 110be803e14Sderaadt curbp = wp1->w_bufp; 111be803e14Sderaadt return TRUE; 112be803e14Sderaadt } 113be803e14Sderaadt 114be803e14Sderaadt /* 1158cad3a2cSmillert * This command makes the current window the only window on the screen. Try 1168cad3a2cSmillert * to set the framing so that "." does not have to move on the display. Some 1178cad3a2cSmillert * care has to be taken to keep the values of dot and mark in the buffer 1188cad3a2cSmillert * structures right if the distruction of a window makes a buffer become 1198cad3a2cSmillert * undisplayed. 120be803e14Sderaadt */ 121be803e14Sderaadt /* ARGSUSED */ 1228cad3a2cSmillert int 123*444cb8bcScloder onlywind(int f, int n) 124be803e14Sderaadt { 1258cad3a2cSmillert MGWIN *wp; 1268cad3a2cSmillert LINE *lp; 1278cad3a2cSmillert int i; 128be803e14Sderaadt 129be803e14Sderaadt while (wheadp != curwp) { 130be803e14Sderaadt wp = wheadp; 131be803e14Sderaadt wheadp = wp->w_wndp; 132be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) { 133be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp; 134be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto; 135be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp; 136be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko; 137be803e14Sderaadt } 138be803e14Sderaadt free((char *)wp); 139be803e14Sderaadt } 140be803e14Sderaadt while (curwp->w_wndp != NULL) { 141be803e14Sderaadt wp = curwp->w_wndp; 142be803e14Sderaadt curwp->w_wndp = wp->w_wndp; 143be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) { 144be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp; 145be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto; 146be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp; 147be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko; 148be803e14Sderaadt } 149be803e14Sderaadt free((char *)wp); 150be803e14Sderaadt } 151be803e14Sderaadt lp = curwp->w_linep; 152be803e14Sderaadt i = curwp->w_toprow; 153be803e14Sderaadt while (i != 0 && lback(lp) != curbp->b_linep) { 154be803e14Sderaadt --i; 155be803e14Sderaadt lp = lback(lp); 156be803e14Sderaadt } 157be803e14Sderaadt curwp->w_toprow = 0; 1588cad3a2cSmillert 1598cad3a2cSmillert /* 2 = mode, echo */ 1608cad3a2cSmillert curwp->w_ntrows = nrow - 2; 161be803e14Sderaadt curwp->w_linep = lp; 162be803e14Sderaadt curwp->w_flag |= WFMODE | WFHARD; 163be803e14Sderaadt return TRUE; 164be803e14Sderaadt } 165be803e14Sderaadt 166be803e14Sderaadt /* 1678cad3a2cSmillert * Split the current window. A window smaller than 3 lines cannot be split. 1688cad3a2cSmillert * The only other error that is possible is a "malloc" failure allocating the 1698cad3a2cSmillert * structure for the new window. 170be803e14Sderaadt */ 171be803e14Sderaadt /* ARGSUSED */ 1728cad3a2cSmillert int 173*444cb8bcScloder splitwind(int f, int n) 174be803e14Sderaadt { 1758cad3a2cSmillert MGWIN *wp, *wp1, *wp2; 1768cad3a2cSmillert LINE *lp; 1778cad3a2cSmillert int ntru, ntrd, ntrl; 178be803e14Sderaadt 179be803e14Sderaadt if (curwp->w_ntrows < 3) { 180be803e14Sderaadt ewprintf("Cannot split a %d line window", curwp->w_ntrows); 181be803e14Sderaadt return (FALSE); 182be803e14Sderaadt } 183b2c89ce4Sart if ((wp = malloc(sizeof(MGWIN))) == NULL) { 184c6029ee2Smillert ewprintf("Can't get %d", sizeof(MGWIN)); 185be803e14Sderaadt return (FALSE); 186be803e14Sderaadt } 1878cad3a2cSmillert 1888cad3a2cSmillert /* displayed twice */ 1898cad3a2cSmillert ++curbp->b_nwnd; 190be803e14Sderaadt wp->w_bufp = curbp; 191be803e14Sderaadt wp->w_dotp = curwp->w_dotp; 192be803e14Sderaadt wp->w_doto = curwp->w_doto; 193be803e14Sderaadt wp->w_markp = curwp->w_markp; 194be803e14Sderaadt wp->w_marko = curwp->w_marko; 195be803e14Sderaadt wp->w_flag = 0; 196be803e14Sderaadt wp->w_force = 0; 197be803e14Sderaadt ntru = (curwp->w_ntrows - 1) / 2; /* Upper size */ 198be803e14Sderaadt ntrl = (curwp->w_ntrows - 1) - ntru; /* Lower size */ 199be803e14Sderaadt lp = curwp->w_linep; 200be803e14Sderaadt ntrd = 0; 201be803e14Sderaadt while (lp != curwp->w_dotp) { 202be803e14Sderaadt ++ntrd; 203be803e14Sderaadt lp = lforw(lp); 204be803e14Sderaadt } 205be803e14Sderaadt lp = curwp->w_linep; 2068cad3a2cSmillert 2078cad3a2cSmillert /* old is upper window */ 2088cad3a2cSmillert if (ntrd <= ntru) { 2098cad3a2cSmillert /* hit mode line */ 2108cad3a2cSmillert if (ntrd == ntru) 211be803e14Sderaadt lp = lforw(lp); 212be803e14Sderaadt curwp->w_ntrows = ntru; 213be803e14Sderaadt wp->w_wndp = curwp->w_wndp; 214be803e14Sderaadt curwp->w_wndp = wp; 215be803e14Sderaadt wp->w_toprow = curwp->w_toprow + ntru + 1; 216be803e14Sderaadt wp->w_ntrows = ntrl; 2178cad3a2cSmillert /* old is lower window */ 2188cad3a2cSmillert } else { 219be803e14Sderaadt wp1 = NULL; 220be803e14Sderaadt wp2 = wheadp; 221be803e14Sderaadt while (wp2 != curwp) { 222be803e14Sderaadt wp1 = wp2; 223be803e14Sderaadt wp2 = wp2->w_wndp; 224be803e14Sderaadt } 225be803e14Sderaadt if (wp1 == NULL) 226be803e14Sderaadt wheadp = wp; 227be803e14Sderaadt else 228be803e14Sderaadt wp1->w_wndp = wp; 229be803e14Sderaadt wp->w_wndp = curwp; 230be803e14Sderaadt wp->w_toprow = curwp->w_toprow; 231be803e14Sderaadt wp->w_ntrows = ntru; 2328cad3a2cSmillert 2338cad3a2cSmillert /* mode line */ 2348cad3a2cSmillert ++ntru; 235be803e14Sderaadt curwp->w_toprow += ntru; 236be803e14Sderaadt curwp->w_ntrows = ntrl; 237be803e14Sderaadt while (ntru--) 238be803e14Sderaadt lp = lforw(lp); 239be803e14Sderaadt } 2408cad3a2cSmillert 2418cad3a2cSmillert /* adjust the top lines if necessary */ 2428cad3a2cSmillert curwp->w_linep = lp; 2438cad3a2cSmillert wp->w_linep = lp; 2448cad3a2cSmillert 245be803e14Sderaadt curwp->w_flag |= WFMODE | WFHARD; 246be803e14Sderaadt wp->w_flag |= WFMODE | WFHARD; 247be803e14Sderaadt return TRUE; 248be803e14Sderaadt } 249be803e14Sderaadt 250be803e14Sderaadt /* 2518cad3a2cSmillert * Enlarge the current window. Find the window that loses space. Make sure 2528cad3a2cSmillert * it is big enough. If so, hack the window descriptions, and ask redisplay 2538cad3a2cSmillert * to do all the hard work. You don't just set "force reframe" because dot 2548cad3a2cSmillert * would move. 255be803e14Sderaadt */ 256be803e14Sderaadt /* ARGSUSED */ 2578cad3a2cSmillert int 258*444cb8bcScloder enlargewind(int f, int n) 259be803e14Sderaadt { 2608cad3a2cSmillert MGWIN *adjwp; 2618cad3a2cSmillert LINE *lp; 2628cad3a2cSmillert int i; 263be803e14Sderaadt 264be803e14Sderaadt if (n < 0) 265be803e14Sderaadt return shrinkwind(f, -n); 266be803e14Sderaadt if (wheadp->w_wndp == NULL) { 267be803e14Sderaadt ewprintf("Only one window"); 268be803e14Sderaadt return FALSE; 269be803e14Sderaadt } 270be803e14Sderaadt if ((adjwp = curwp->w_wndp) == NULL) { 271be803e14Sderaadt adjwp = wheadp; 272be803e14Sderaadt while (adjwp->w_wndp != curwp) 273be803e14Sderaadt adjwp = adjwp->w_wndp; 274be803e14Sderaadt } 275be803e14Sderaadt if (adjwp->w_ntrows <= n) { 276be803e14Sderaadt ewprintf("Impossible change"); 277be803e14Sderaadt return FALSE; 278be803e14Sderaadt } 2798cad3a2cSmillert 2808cad3a2cSmillert /* shrink below */ 2818cad3a2cSmillert if (curwp->w_wndp == adjwp) { 282be803e14Sderaadt lp = adjwp->w_linep; 283be803e14Sderaadt for (i = 0; i < n && lp != adjwp->w_bufp->b_linep; ++i) 284be803e14Sderaadt lp = lforw(lp); 285be803e14Sderaadt adjwp->w_linep = lp; 286be803e14Sderaadt adjwp->w_toprow += n; 2878cad3a2cSmillert /* shrink above */ 2888cad3a2cSmillert } else { 289be803e14Sderaadt lp = curwp->w_linep; 290be803e14Sderaadt for (i = 0; i < n && lback(lp) != curbp->b_linep; ++i) 291be803e14Sderaadt lp = lback(lp); 292be803e14Sderaadt curwp->w_linep = lp; 293be803e14Sderaadt curwp->w_toprow -= n; 294be803e14Sderaadt } 295be803e14Sderaadt curwp->w_ntrows += n; 296be803e14Sderaadt adjwp->w_ntrows -= n; 297be803e14Sderaadt curwp->w_flag |= WFMODE | WFHARD; 298be803e14Sderaadt adjwp->w_flag |= WFMODE | WFHARD; 299be803e14Sderaadt return TRUE; 300be803e14Sderaadt } 301be803e14Sderaadt 302be803e14Sderaadt /* 3038cad3a2cSmillert * Shrink the current window. Find the window that gains space. Hack at the 3048cad3a2cSmillert * window descriptions. Ask the redisplay to do all the hard work. 305be803e14Sderaadt */ 3068cad3a2cSmillert int 307*444cb8bcScloder shrinkwind(int f, int n) 308be803e14Sderaadt { 3098cad3a2cSmillert MGWIN *adjwp; 3108cad3a2cSmillert LINE *lp; 3118cad3a2cSmillert int i; 312be803e14Sderaadt 313be803e14Sderaadt if (n < 0) 314be803e14Sderaadt return enlargewind(f, -n); 315be803e14Sderaadt if (wheadp->w_wndp == NULL) { 316be803e14Sderaadt ewprintf("Only one window"); 317be803e14Sderaadt return FALSE; 318be803e14Sderaadt } 319be803e14Sderaadt /* 320be803e14Sderaadt * Bit of flakiness - KRANDOM means it was an internal call, and 321be803e14Sderaadt * to be trusted implicitly about sizes. 322be803e14Sderaadt */ 323be803e14Sderaadt if (!(f & FFRAND) && curwp->w_ntrows <= n) { 324be803e14Sderaadt ewprintf("Impossible change"); 325be803e14Sderaadt return (FALSE); 326be803e14Sderaadt } 327be803e14Sderaadt if ((adjwp = curwp->w_wndp) == NULL) { 328be803e14Sderaadt adjwp = wheadp; 329be803e14Sderaadt while (adjwp->w_wndp != curwp) 330be803e14Sderaadt adjwp = adjwp->w_wndp; 331be803e14Sderaadt } 3328cad3a2cSmillert 3338cad3a2cSmillert /* grow below */ 3348cad3a2cSmillert if (curwp->w_wndp == adjwp) { 335be803e14Sderaadt lp = adjwp->w_linep; 336be803e14Sderaadt for (i = 0; i < n && lback(lp) != adjwp->w_bufp->b_linep; ++i) 337be803e14Sderaadt lp = lback(lp); 338be803e14Sderaadt adjwp->w_linep = lp; 339be803e14Sderaadt adjwp->w_toprow -= n; 3408cad3a2cSmillert /* grow above */ 3418cad3a2cSmillert } else { 342be803e14Sderaadt lp = curwp->w_linep; 343be803e14Sderaadt for (i = 0; i < n && lp != curbp->b_linep; ++i) 344be803e14Sderaadt lp = lforw(lp); 345be803e14Sderaadt curwp->w_linep = lp; 346be803e14Sderaadt curwp->w_toprow += n; 347be803e14Sderaadt } 348be803e14Sderaadt curwp->w_ntrows -= n; 349be803e14Sderaadt adjwp->w_ntrows += n; 350be803e14Sderaadt curwp->w_flag |= WFMODE | WFHARD; 351be803e14Sderaadt adjwp->w_flag |= WFMODE | WFHARD; 352be803e14Sderaadt return (TRUE); 353be803e14Sderaadt } 354be803e14Sderaadt 355be803e14Sderaadt /* 3568cad3a2cSmillert * Delete current window. Call shrink-window to do the screen updating, then 3578cad3a2cSmillert * throw away the window. 358be803e14Sderaadt */ 359be803e14Sderaadt /* ARGSUSED */ 3608cad3a2cSmillert int 361*444cb8bcScloder delwind(int f, int n) 362be803e14Sderaadt { 3638cad3a2cSmillert MGWIN *wp, *nwp; 364be803e14Sderaadt 365be803e14Sderaadt wp = curwp; /* Cheap... */ 3668cad3a2cSmillert 367be803e14Sderaadt /* shrinkwind returning false means only one window... */ 368be803e14Sderaadt if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE) 369be803e14Sderaadt return FALSE; 370be803e14Sderaadt if (--wp->w_bufp->b_nwnd == 0) { 371be803e14Sderaadt wp->w_bufp->b_dotp = wp->w_dotp; 372be803e14Sderaadt wp->w_bufp->b_doto = wp->w_doto; 373be803e14Sderaadt wp->w_bufp->b_markp = wp->w_markp; 374be803e14Sderaadt wp->w_bufp->b_marko = wp->w_marko; 375be803e14Sderaadt } 3768cad3a2cSmillert 377be803e14Sderaadt /* since shrinkwind did't crap out, we know we have a second window */ 378371f5030Smillert if (wp == wheadp) 379371f5030Smillert wheadp = curwp = wp->w_wndp; 380371f5030Smillert else if ((curwp = wp->w_wndp) == NULL) 381371f5030Smillert curwp = wheadp; 382be803e14Sderaadt curbp = curwp->w_bufp; 383be803e14Sderaadt for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp) 384be803e14Sderaadt if (nwp->w_wndp == wp) { 385be803e14Sderaadt nwp->w_wndp = wp->w_wndp; 386be803e14Sderaadt break; 387be803e14Sderaadt } 388be803e14Sderaadt free((char *)wp); 389be803e14Sderaadt return TRUE; 390be803e14Sderaadt } 3918cad3a2cSmillert 392be803e14Sderaadt /* 3938cad3a2cSmillert * Pick a window for a pop-up. Split the screen if there is only one window. 3948cad3a2cSmillert * Pick the uppermost window that isn't the current window. An LRU algorithm 3958cad3a2cSmillert * might be better. Return a pointer, or NULL on error. 396be803e14Sderaadt */ 397c6029ee2Smillert MGWIN * 398*444cb8bcScloder wpopup(void) 399371f5030Smillert { 4008cad3a2cSmillert MGWIN *wp; 401be803e14Sderaadt 4028b29b1f7Sderaadt if (wheadp->w_wndp == NULL && 4038b29b1f7Sderaadt splitwind(FFRAND, 0) == FALSE) 404be803e14Sderaadt return NULL; 4058cad3a2cSmillert 4068cad3a2cSmillert /* find a window to use */ 4078cad3a2cSmillert wp = wheadp; 4088cad3a2cSmillert 409be803e14Sderaadt while (wp != NULL && wp == curwp) 410be803e14Sderaadt wp = wp->w_wndp; 411be803e14Sderaadt return wp; 412be803e14Sderaadt } 413