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