1 /* $OpenBSD: window.c,v 1.5 2001/01/29 01:58:10 niklas Exp $ */ 2 3 /* 4 * Window handling. 5 */ 6 7 #include "def.h" 8 9 /* 10 * Reposition dot in the current window to line "n". If the argument is 11 * positive, it is that line. If it is negative it is that line from the 12 * bottom. If it is 0 the window is centered (this is what the standard 13 * redisplay code does). If GOSREC is undefined, default is 0, so it acts 14 * like GNU. If GOSREC is defined, with no argument it defaults to 1 and 15 * works like in Gosling. 16 */ 17 /* ARGSUSED */ 18 int 19 reposition(f, n) 20 int f, n; 21 { 22 #ifndef GOSREC 23 curwp->w_force = (f & FFARG) ? (n >= 0 ? n + 1 : n) : 0; 24 #else /* !GOSREC */ 25 curwp->w_force = n; 26 #endif /* !GOSREC */ 27 curwp->w_flag |= WFFORCE; 28 sgarbf = TRUE; 29 return TRUE; 30 } 31 32 /* 33 * Refresh the display. A call is made to the "ttresize" entry in the 34 * terminal handler, which tries to reset "nrow" and "ncol". They will, 35 * however, never be set outside of the NROW or NCOL range. If the display 36 * changed size, arrange that everything is redone, then call "update" to 37 * fix the display. We do this so the new size can be displayed. In the 38 * normal case the call to "update" in "main.c" refreshes the screen, and 39 * all of the windows need not be recomputed. Note that when you get to the 40 * "display unusable" message, the screen will be messed up. If you make the 41 * window bigger again, and send another command, everything will get fixed! 42 */ 43 /* ARGSUSED */ 44 int 45 refresh(f, n) 46 int f, n; 47 { 48 MGWIN *wp; 49 int oldnrow; 50 int oldncol; 51 52 oldnrow = nrow; 53 oldncol = ncol; 54 ttresize(); 55 if (nrow != oldnrow || ncol != oldncol) { 56 57 /* find last */ 58 wp = wheadp; 59 while (wp->w_wndp != NULL) 60 wp = wp->w_wndp; 61 62 /* check if too small */ 63 if (nrow < wp->w_toprow + 3) { 64 ewprintf("Display unusable"); 65 return (FALSE); 66 } 67 wp->w_ntrows = nrow - wp->w_toprow - 2; 68 sgarbf = TRUE; 69 update(); 70 ewprintf("New size %d by %d", nrow, ncol); 71 } else 72 sgarbf = TRUE; 73 return TRUE; 74 } 75 76 /* 77 * The command to make the next window (next => down the screen) the current 78 * window. There are no real errors, although the command does nothing if 79 * there is only 1 window on the screen. 80 */ 81 /* ARGSUSED */ 82 int 83 nextwind(f, n) 84 int f, n; 85 { 86 MGWIN *wp; 87 88 if ((wp = curwp->w_wndp) == NULL) 89 wp = wheadp; 90 curwp = wp; 91 curbp = wp->w_bufp; 92 return TRUE; 93 } 94 95 #ifdef GOSMACS 96 97 /* not in Gnu Emacs */ 98 /* 99 * This command makes the previous window (previous => up the screen) the 100 * current window. There are no errors, although the command does not do 101 * a lot if there is only 1 window. 102 */ 103 /* ARGSUSED */ 104 int 105 prevwind(f, n) 106 int f, n; 107 { 108 MGWIN *wp1, *wp2; 109 110 wp1 = wheadp; 111 wp2 = curwp; 112 if (wp1 == wp2) 113 wp2 = NULL; 114 while (wp1->w_wndp != wp2) 115 wp1 = wp1->w_wndp; 116 curwp = wp1; 117 curbp = wp1->w_bufp; 118 return TRUE; 119 } 120 #endif /* GOSEMACS */ 121 122 /* 123 * This command makes the current window the only window on the screen. Try 124 * to set the framing so that "." does not have to move on the display. Some 125 * care has to be taken to keep the values of dot and mark in the buffer 126 * structures right if the distruction of a window makes a buffer become 127 * undisplayed. 128 */ 129 /* ARGSUSED */ 130 int 131 onlywind(f, n) 132 int f, n; 133 { 134 MGWIN *wp; 135 LINE *lp; 136 int i; 137 138 while (wheadp != curwp) { 139 wp = wheadp; 140 wheadp = wp->w_wndp; 141 if (--wp->w_bufp->b_nwnd == 0) { 142 wp->w_bufp->b_dotp = wp->w_dotp; 143 wp->w_bufp->b_doto = wp->w_doto; 144 wp->w_bufp->b_markp = wp->w_markp; 145 wp->w_bufp->b_marko = wp->w_marko; 146 } 147 free((char *)wp); 148 } 149 while (curwp->w_wndp != NULL) { 150 wp = curwp->w_wndp; 151 curwp->w_wndp = wp->w_wndp; 152 if (--wp->w_bufp->b_nwnd == 0) { 153 wp->w_bufp->b_dotp = wp->w_dotp; 154 wp->w_bufp->b_doto = wp->w_doto; 155 wp->w_bufp->b_markp = wp->w_markp; 156 wp->w_bufp->b_marko = wp->w_marko; 157 } 158 free((char *)wp); 159 } 160 lp = curwp->w_linep; 161 i = curwp->w_toprow; 162 while (i != 0 && lback(lp) != curbp->b_linep) { 163 --i; 164 lp = lback(lp); 165 } 166 curwp->w_toprow = 0; 167 168 /* 2 = mode, echo */ 169 curwp->w_ntrows = nrow - 2; 170 curwp->w_linep = lp; 171 curwp->w_flag |= WFMODE | WFHARD; 172 return TRUE; 173 } 174 175 /* 176 * Split the current window. A window smaller than 3 lines cannot be split. 177 * The only other error that is possible is a "malloc" failure allocating the 178 * structure for the new window. 179 */ 180 /* ARGSUSED */ 181 int 182 splitwind(f, n) 183 int f, n; 184 { 185 MGWIN *wp, *wp1, *wp2; 186 LINE *lp; 187 int ntru, ntrd, ntrl; 188 189 if (curwp->w_ntrows < 3) { 190 ewprintf("Cannot split a %d line window", curwp->w_ntrows); 191 return (FALSE); 192 } 193 if ((wp = (MGWIN *)malloc(sizeof(MGWIN))) == NULL) { 194 ewprintf("Can't get %d", sizeof(MGWIN)); 195 return (FALSE); 196 } 197 198 /* displayed twice */ 199 ++curbp->b_nwnd; 200 wp->w_bufp = curbp; 201 wp->w_dotp = curwp->w_dotp; 202 wp->w_doto = curwp->w_doto; 203 wp->w_markp = curwp->w_markp; 204 wp->w_marko = curwp->w_marko; 205 wp->w_flag = 0; 206 wp->w_force = 0; 207 ntru = (curwp->w_ntrows - 1) / 2; /* Upper size */ 208 ntrl = (curwp->w_ntrows - 1) - ntru; /* Lower size */ 209 lp = curwp->w_linep; 210 ntrd = 0; 211 while (lp != curwp->w_dotp) { 212 ++ntrd; 213 lp = lforw(lp); 214 } 215 lp = curwp->w_linep; 216 217 /* old is upper window */ 218 if (ntrd <= ntru) { 219 /* hit mode line */ 220 if (ntrd == ntru) 221 lp = lforw(lp); 222 curwp->w_ntrows = ntru; 223 wp->w_wndp = curwp->w_wndp; 224 curwp->w_wndp = wp; 225 wp->w_toprow = curwp->w_toprow + ntru + 1; 226 wp->w_ntrows = ntrl; 227 /* old is lower window */ 228 } else { 229 wp1 = NULL; 230 wp2 = wheadp; 231 while (wp2 != curwp) { 232 wp1 = wp2; 233 wp2 = wp2->w_wndp; 234 } 235 if (wp1 == NULL) 236 wheadp = wp; 237 else 238 wp1->w_wndp = wp; 239 wp->w_wndp = curwp; 240 wp->w_toprow = curwp->w_toprow; 241 wp->w_ntrows = ntru; 242 243 /* mode line */ 244 ++ntru; 245 curwp->w_toprow += ntru; 246 curwp->w_ntrows = ntrl; 247 while (ntru--) 248 lp = lforw(lp); 249 } 250 251 /* adjust the top lines if necessary */ 252 curwp->w_linep = lp; 253 wp->w_linep = lp; 254 255 curwp->w_flag |= WFMODE | WFHARD; 256 wp->w_flag |= WFMODE | WFHARD; 257 return TRUE; 258 } 259 260 /* 261 * Enlarge the current window. Find the window that loses space. Make sure 262 * it is big enough. If so, hack the window descriptions, and ask redisplay 263 * to do all the hard work. You don't just set "force reframe" because dot 264 * would move. 265 */ 266 /* ARGSUSED */ 267 int 268 enlargewind(f, n) 269 int f, n; 270 { 271 MGWIN *adjwp; 272 LINE *lp; 273 int i; 274 275 if (n < 0) 276 return shrinkwind(f, -n); 277 if (wheadp->w_wndp == NULL) { 278 ewprintf("Only one window"); 279 return FALSE; 280 } 281 if ((adjwp = curwp->w_wndp) == NULL) { 282 adjwp = wheadp; 283 while (adjwp->w_wndp != curwp) 284 adjwp = adjwp->w_wndp; 285 } 286 if (adjwp->w_ntrows <= n) { 287 ewprintf("Impossible change"); 288 return FALSE; 289 } 290 291 /* shrink below */ 292 if (curwp->w_wndp == adjwp) { 293 lp = adjwp->w_linep; 294 for (i = 0; i < n && lp != adjwp->w_bufp->b_linep; ++i) 295 lp = lforw(lp); 296 adjwp->w_linep = lp; 297 adjwp->w_toprow += n; 298 /* shrink above */ 299 } else { 300 lp = curwp->w_linep; 301 for (i = 0; i < n && lback(lp) != curbp->b_linep; ++i) 302 lp = lback(lp); 303 curwp->w_linep = lp; 304 curwp->w_toprow -= n; 305 } 306 curwp->w_ntrows += n; 307 adjwp->w_ntrows -= n; 308 curwp->w_flag |= WFMODE | WFHARD; 309 adjwp->w_flag |= WFMODE | WFHARD; 310 return TRUE; 311 } 312 313 /* 314 * Shrink the current window. Find the window that gains space. Hack at the 315 * window descriptions. Ask the redisplay to do all the hard work. 316 */ 317 int 318 shrinkwind(f, n) 319 int f, n; 320 { 321 MGWIN *adjwp; 322 LINE *lp; 323 int i; 324 325 if (n < 0) 326 return enlargewind(f, -n); 327 if (wheadp->w_wndp == NULL) { 328 ewprintf("Only one window"); 329 return FALSE; 330 } 331 /* 332 * Bit of flakiness - KRANDOM means it was an internal call, and 333 * to be trusted implicitly about sizes. 334 */ 335 if (!(f & FFRAND) && curwp->w_ntrows <= n) { 336 ewprintf("Impossible change"); 337 return (FALSE); 338 } 339 if ((adjwp = curwp->w_wndp) == NULL) { 340 adjwp = wheadp; 341 while (adjwp->w_wndp != curwp) 342 adjwp = adjwp->w_wndp; 343 } 344 345 /* grow below */ 346 if (curwp->w_wndp == adjwp) { 347 lp = adjwp->w_linep; 348 for (i = 0; i < n && lback(lp) != adjwp->w_bufp->b_linep; ++i) 349 lp = lback(lp); 350 adjwp->w_linep = lp; 351 adjwp->w_toprow -= n; 352 /* grow above */ 353 } else { 354 lp = curwp->w_linep; 355 for (i = 0; i < n && lp != curbp->b_linep; ++i) 356 lp = lforw(lp); 357 curwp->w_linep = lp; 358 curwp->w_toprow += n; 359 } 360 curwp->w_ntrows -= n; 361 adjwp->w_ntrows += n; 362 curwp->w_flag |= WFMODE | WFHARD; 363 adjwp->w_flag |= WFMODE | WFHARD; 364 return (TRUE); 365 } 366 367 /* 368 * Delete current window. Call shrink-window to do the screen updating, then 369 * throw away the window. 370 */ 371 /* ARGSUSED */ 372 int 373 delwind(f, n) 374 int f, n; 375 { 376 MGWIN *wp, *nwp; 377 378 wp = curwp; /* Cheap... */ 379 380 /* shrinkwind returning false means only one window... */ 381 if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE) 382 return FALSE; 383 if (--wp->w_bufp->b_nwnd == 0) { 384 wp->w_bufp->b_dotp = wp->w_dotp; 385 wp->w_bufp->b_doto = wp->w_doto; 386 wp->w_bufp->b_markp = wp->w_markp; 387 wp->w_bufp->b_marko = wp->w_marko; 388 } 389 390 /* since shrinkwind did't crap out, we know we have a second window */ 391 if (wp == wheadp) 392 wheadp = curwp = wp->w_wndp; 393 else if ((curwp = wp->w_wndp) == NULL) 394 curwp = wheadp; 395 curbp = curwp->w_bufp; 396 for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp) 397 if (nwp->w_wndp == wp) { 398 nwp->w_wndp = wp->w_wndp; 399 break; 400 } 401 free((char *)wp); 402 return TRUE; 403 } 404 405 /* 406 * Pick a window for a pop-up. Split the screen if there is only one window. 407 * Pick the uppermost window that isn't the current window. An LRU algorithm 408 * might be better. Return a pointer, or NULL on error. 409 */ 410 MGWIN * 411 wpopup() 412 { 413 MGWIN *wp; 414 415 if (wheadp->w_wndp == NULL 416 && splitwind(FFRAND, 0) == FALSE) 417 return NULL; 418 419 /* find a window to use */ 420 wp = wheadp; 421 422 while (wp != NULL && wp == curwp) 423 wp = wp->w_wndp; 424 return wp; 425 } 426