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