layout.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <stdlib.h>
  19. #include "tmux.h"
  20. /*
  21. * The window layout is a tree of cells each of which can be one of: a
  22. * left-right container for a list of cells, a top-bottom container for a list
  23. * of cells, or a container for a window pane.
  24. *
  25. * Each window has a pointer to the root of its layout tree (containing its
  26. * panes), every pane has a pointer back to the cell containing it, and each
  27. * cell a pointer to its parent cell.
  28. */
  29. int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int);
  30. int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int);
  31. struct layout_cell *
  32. layout_create_cell(struct layout_cell *lcparent)
  33. {
  34. struct layout_cell *lc;
  35. lc = xmalloc(sizeof *lc);
  36. lc->type = LAYOUT_WINDOWPANE;
  37. lc->parent = lcparent;
  38. TAILQ_INIT(&lc->cells);
  39. lc->sx = UINT_MAX;
  40. lc->sy = UINT_MAX;
  41. lc->xoff = UINT_MAX;
  42. lc->yoff = UINT_MAX;
  43. lc->wp = NULL;
  44. return (lc);
  45. }
  46. void
  47. layout_free_cell(struct layout_cell *lc)
  48. {
  49. struct layout_cell *lcchild;
  50. switch (lc->type) {
  51. case LAYOUT_LEFTRIGHT:
  52. case LAYOUT_TOPBOTTOM:
  53. while (!TAILQ_EMPTY(&lc->cells)) {
  54. lcchild = TAILQ_FIRST(&lc->cells);
  55. TAILQ_REMOVE(&lc->cells, lcchild, entry);
  56. layout_free_cell(lcchild);
  57. }
  58. break;
  59. case LAYOUT_WINDOWPANE:
  60. if (lc->wp != NULL)
  61. lc->wp->layout_cell = NULL;
  62. break;
  63. }
  64. free(lc);
  65. }
  66. void
  67. layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
  68. {
  69. struct layout_cell *lcchild;
  70. log_debug("%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n,
  71. " ", lc, lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
  72. lc->sy);
  73. switch (lc->type) {
  74. case LAYOUT_LEFTRIGHT:
  75. case LAYOUT_TOPBOTTOM:
  76. TAILQ_FOREACH(lcchild, &lc->cells, entry)
  77. layout_print_cell(lcchild, hdr, n + 1);
  78. break;
  79. case LAYOUT_WINDOWPANE:
  80. break;
  81. }
  82. }
  83. void
  84. layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
  85. u_int yoff)
  86. {
  87. lc->sx = sx;
  88. lc->sy = sy;
  89. lc->xoff = xoff;
  90. lc->yoff = yoff;
  91. }
  92. void
  93. layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
  94. {
  95. lc->type = LAYOUT_WINDOWPANE;
  96. TAILQ_INIT(&lc->cells);
  97. wp->layout_cell = lc;
  98. lc->wp = wp;
  99. }
  100. void
  101. layout_make_node(struct layout_cell *lc, enum layout_type type)
  102. {
  103. if (type == LAYOUT_WINDOWPANE)
  104. fatalx("bad layout type");
  105. lc->type = type;
  106. TAILQ_INIT(&lc->cells);
  107. if (lc->wp != NULL)
  108. lc->wp->layout_cell = NULL;
  109. lc->wp = NULL;
  110. }
  111. /* Fix cell offsets based on their sizes. */
  112. void
  113. layout_fix_offsets(struct layout_cell *lc)
  114. {
  115. struct layout_cell *lcchild;
  116. u_int xoff, yoff;
  117. if (lc->type == LAYOUT_LEFTRIGHT) {
  118. xoff = lc->xoff;
  119. TAILQ_FOREACH(lcchild, &lc->cells, entry) {
  120. lcchild->xoff = xoff;
  121. lcchild->yoff = lc->yoff;
  122. if (lcchild->type != LAYOUT_WINDOWPANE)
  123. layout_fix_offsets(lcchild);
  124. xoff += lcchild->sx + 1;
  125. }
  126. } else {
  127. yoff = lc->yoff;
  128. TAILQ_FOREACH(lcchild, &lc->cells, entry) {
  129. lcchild->xoff = lc->xoff;
  130. lcchild->yoff = yoff;
  131. if (lcchild->type != LAYOUT_WINDOWPANE)
  132. layout_fix_offsets(lcchild);
  133. yoff += lcchild->sy + 1;
  134. }
  135. }
  136. }
  137. /* Update pane offsets and sizes based on their cells. */
  138. void
  139. layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
  140. {
  141. struct window_pane *wp;
  142. struct layout_cell *lc;
  143. u_int sx, sy;
  144. TAILQ_FOREACH(wp, &w->panes, entry) {
  145. if ((lc = wp->layout_cell) == NULL)
  146. continue;
  147. wp->xoff = lc->xoff;
  148. wp->yoff = lc->yoff;
  149. /*
  150. * Layout cells are limited by the smallest size of other cells
  151. * within the same row or column; if this isn't the case
  152. * resizing becomes difficult.
  153. *
  154. * However, panes do not have to take up their entire cell, so
  155. * they can be cropped to the window edge if the layout
  156. * overflows and they are partly visible.
  157. *
  158. * This stops cells being hidden unnecessarily.
  159. */
  160. /*
  161. * Work out the horizontal size. If the pane is actually
  162. * outside the window or the entire pane is already visible,
  163. * don't crop.
  164. */
  165. if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx)
  166. sx = lc->sx;
  167. else {
  168. sx = wsx - lc->xoff;
  169. if (sx < 1)
  170. sx = lc->sx;
  171. }
  172. /*
  173. * Similarly for the vertical size; the minimum vertical size
  174. * is two because scroll regions cannot be one line.
  175. */
  176. if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy)
  177. sy = lc->sy;
  178. else {
  179. sy = wsy - lc->yoff;
  180. if (sy < 2)
  181. sy = lc->sy;
  182. }
  183. window_pane_resize(wp, sx, sy);
  184. }
  185. }
  186. /* Count the number of available cells in a layout. */
  187. u_int
  188. layout_count_cells(struct layout_cell *lc)
  189. {
  190. struct layout_cell *lcchild;
  191. u_int n;
  192. switch (lc->type) {
  193. case LAYOUT_WINDOWPANE:
  194. return (1);
  195. case LAYOUT_LEFTRIGHT:
  196. case LAYOUT_TOPBOTTOM:
  197. n = 0;
  198. TAILQ_FOREACH(lcchild, &lc->cells, entry)
  199. n += layout_count_cells(lcchild);
  200. return (n);
  201. default:
  202. fatalx("bad layout type");
  203. }
  204. }
  205. /* Calculate how much size is available to be removed from a cell. */
  206. u_int
  207. layout_resize_check(struct layout_cell *lc, enum layout_type type)
  208. {
  209. struct layout_cell *lcchild;
  210. u_int available, minimum;
  211. if (lc->type == LAYOUT_WINDOWPANE) {
  212. /* Space available in this cell only. */
  213. if (type == LAYOUT_LEFTRIGHT)
  214. available = lc->sx;
  215. else
  216. available = lc->sy;
  217. if (available > PANE_MINIMUM)
  218. available -= PANE_MINIMUM;
  219. else
  220. available = 0;
  221. } else if (lc->type == type) {
  222. /* Same type: total of available space in all child cells. */
  223. available = 0;
  224. TAILQ_FOREACH(lcchild, &lc->cells, entry)
  225. available += layout_resize_check(lcchild, type);
  226. } else {
  227. /* Different type: minimum of available space in child cells. */
  228. minimum = UINT_MAX;
  229. TAILQ_FOREACH(lcchild, &lc->cells, entry) {
  230. available = layout_resize_check(lcchild, type);
  231. if (available < minimum)
  232. minimum = available;
  233. }
  234. available = minimum;
  235. }
  236. return (available);
  237. }
  238. /*
  239. * Adjust cell size evenly, including altering its children. This function
  240. * expects the change to have already been bounded to the space available.
  241. */
  242. void
  243. layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
  244. {
  245. struct layout_cell *lcchild;
  246. /* Adjust the cell size. */
  247. if (type == LAYOUT_LEFTRIGHT)
  248. lc->sx += change;
  249. else
  250. lc->sy += change;
  251. /* If this is a leaf cell, that is all that is necessary. */
  252. if (type == LAYOUT_WINDOWPANE)
  253. return;
  254. /* Child cell runs in a different direction. */
  255. if (lc->type != type) {
  256. TAILQ_FOREACH(lcchild, &lc->cells, entry)
  257. layout_resize_adjust(lcchild, type, change);
  258. return;
  259. }
  260. /*
  261. * Child cell runs in the same direction. Adjust each child equally
  262. * until no further change is possible.
  263. */
  264. while (change != 0) {
  265. TAILQ_FOREACH(lcchild, &lc->cells, entry) {
  266. if (change == 0)
  267. break;
  268. if (change > 0) {
  269. layout_resize_adjust(lcchild, type, 1);
  270. change--;
  271. continue;
  272. }
  273. if (layout_resize_check(lcchild, type) > 0) {
  274. layout_resize_adjust(lcchild, type, -1);
  275. change++;
  276. }
  277. }
  278. }
  279. }
  280. /* Destroy a cell and redistribute the space. */
  281. void
  282. layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
  283. {
  284. struct layout_cell *lcother, *lcparent;
  285. /*
  286. * If no parent, this is the last pane so window close is imminent and
  287. * there is no need to resize anything.
  288. */
  289. lcparent = lc->parent;
  290. if (lcparent == NULL) {
  291. layout_free_cell(lc);
  292. *lcroot = NULL;
  293. return;
  294. }
  295. /* Merge the space into the previous or next cell. */
  296. if (lc == TAILQ_FIRST(&lcparent->cells))
  297. lcother = TAILQ_NEXT(lc, entry);
  298. else
  299. lcother = TAILQ_PREV(lc, layout_cells, entry);
  300. if (lcparent->type == LAYOUT_LEFTRIGHT)
  301. layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
  302. else
  303. layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
  304. /* Remove this from the parent's list. */
  305. TAILQ_REMOVE(&lcparent->cells, lc, entry);
  306. layout_free_cell(lc);
  307. /*
  308. * If the parent now has one cell, remove the parent from the tree and
  309. * replace it by that cell.
  310. */
  311. lc = TAILQ_FIRST(&lcparent->cells);
  312. if (TAILQ_NEXT(lc, entry) == NULL) {
  313. TAILQ_REMOVE(&lcparent->cells, lc, entry);
  314. lc->parent = lcparent->parent;
  315. if (lc->parent == NULL) {
  316. lc->xoff = 0; lc->yoff = 0;
  317. *lcroot = lc;
  318. } else
  319. TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
  320. layout_free_cell(lcparent);
  321. }
  322. }
  323. void
  324. layout_init(struct window *w, struct window_pane *wp)
  325. {
  326. struct layout_cell *lc;
  327. lc = w->layout_root = layout_create_cell(NULL);
  328. layout_set_size(lc, w->sx, w->sy, 0, 0);
  329. layout_make_leaf(lc, wp);
  330. layout_fix_panes(w, w->sx, w->sy);
  331. }
  332. void
  333. layout_free(struct window *w)
  334. {
  335. layout_free_cell(w->layout_root);
  336. }
  337. /* Resize the entire layout after window resize. */
  338. void
  339. layout_resize(struct window *w, u_int sx, u_int sy)
  340. {
  341. struct layout_cell *lc = w->layout_root;
  342. int xlimit, ylimit, xchange, ychange;
  343. /*
  344. * Adjust horizontally. Do not attempt to reduce the layout lower than
  345. * the minimum (more than the amount returned by layout_resize_check).
  346. *
  347. * This can mean that the window size is smaller than the total layout
  348. * size: redrawing this is handled at a higher level, but it does leave
  349. * a problem with growing the window size here: if the current size is
  350. * < the minimum, growing proportionately by adding to each pane is
  351. * wrong as it would keep the layout size larger than the window size.
  352. * Instead, spread the difference between the minimum and the new size
  353. * out proportionately - this should leave the layout fitting the new
  354. * window size.
  355. */
  356. xchange = sx - w->sx;
  357. xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT);
  358. if (xchange < 0 && xchange < -xlimit)
  359. xchange = -xlimit;
  360. if (xlimit == 0) {
  361. if (sx <= lc->sx) /* lc->sx is minimum possible */
  362. xchange = 0;
  363. else
  364. xchange = sx - lc->sx;
  365. }
  366. if (xchange != 0)
  367. layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange);
  368. /* Adjust vertically in a similar fashion. */
  369. ychange = sy - w->sy;
  370. ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM);
  371. if (ychange < 0 && ychange < -ylimit)
  372. ychange = -ylimit;
  373. if (ylimit == 0) {
  374. if (sy <= lc->sy) /* lc->sy is minimum possible */
  375. ychange = 0;
  376. else
  377. ychange = sy - lc->sy;
  378. }
  379. if (ychange != 0)
  380. layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange);
  381. /* Fix cell offsets. */
  382. layout_fix_offsets(lc);
  383. layout_fix_panes(w, sx, sy);
  384. }
  385. /* Resize a pane to an absolute size. */
  386. void
  387. layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
  388. u_int new_size)
  389. {
  390. struct layout_cell *lc, *lcparent;
  391. int change, size;
  392. lc = wp->layout_cell;
  393. /* Find next parent of the same type. */
  394. lcparent = lc->parent;
  395. while (lcparent != NULL && lcparent->type != type) {
  396. lc = lcparent;
  397. lcparent = lc->parent;
  398. }
  399. if (lcparent == NULL)
  400. return;
  401. /* Work out the size adjustment. */
  402. if (type == LAYOUT_LEFTRIGHT)
  403. size = lc->sx;
  404. else
  405. size = lc->sy;
  406. if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
  407. change = size - new_size;
  408. else
  409. change = new_size - size;
  410. /* Resize the pane. */
  411. layout_resize_pane(wp, type, change);
  412. }
  413. /* Resize a single pane within the layout. */
  414. void
  415. layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
  416. {
  417. struct layout_cell *lc, *lcparent;
  418. int needed, size;
  419. lc = wp->layout_cell;
  420. /* Find next parent of the same type. */
  421. lcparent = lc->parent;
  422. while (lcparent != NULL && lcparent->type != type) {
  423. lc = lcparent;
  424. lcparent = lc->parent;
  425. }
  426. if (lcparent == NULL)
  427. return;
  428. /* If this is the last cell, move back one. */
  429. if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
  430. lc = TAILQ_PREV(lc, layout_cells, entry);
  431. /* Grow or shrink the cell. */
  432. needed = change;
  433. while (needed != 0) {
  434. if (change > 0) {
  435. size = layout_resize_pane_grow(lc, type, needed);
  436. needed -= size;
  437. } else {
  438. size = layout_resize_pane_shrink(lc, type, needed);
  439. needed += size;
  440. }
  441. if (size == 0) /* no more change possible */
  442. break;
  443. }
  444. /* Fix cell offsets. */
  445. layout_fix_offsets(wp->window->layout_root);
  446. layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
  447. notify_window_layout_changed(wp->window);
  448. }
  449. /* Helper function to grow pane. */
  450. int
  451. layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
  452. int needed)
  453. {
  454. struct layout_cell *lcadd, *lcremove;
  455. u_int size;
  456. /* Growing. Always add to the current cell. */
  457. lcadd = lc;
  458. /* Look towards the tail for a suitable cell for reduction. */
  459. lcremove = TAILQ_NEXT(lc, entry);
  460. while (lcremove != NULL) {
  461. size = layout_resize_check(lcremove, type);
  462. if (size > 0)
  463. break;
  464. lcremove = TAILQ_NEXT(lcremove, entry);
  465. }
  466. /* If none found, look towards the head. */
  467. if (lcremove == NULL) {
  468. lcremove = TAILQ_PREV(lc, layout_cells, entry);
  469. while (lcremove != NULL) {
  470. size = layout_resize_check(lcremove, type);
  471. if (size > 0)
  472. break;
  473. lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
  474. }
  475. if (lcremove == NULL)
  476. return (0);
  477. }
  478. /* Change the cells. */
  479. if (size > (u_int) needed)
  480. size = needed;
  481. layout_resize_adjust(lcadd, type, size);
  482. layout_resize_adjust(lcremove, type, -size);
  483. return (size);
  484. }
  485. /* Helper function to shrink pane. */
  486. int
  487. layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
  488. int needed)
  489. {
  490. struct layout_cell *lcadd, *lcremove;
  491. u_int size;
  492. /* Shrinking. Find cell to remove from by walking towards head. */
  493. lcremove = lc;
  494. do {
  495. size = layout_resize_check(lcremove, type);
  496. if (size != 0)
  497. break;
  498. lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
  499. } while (lcremove != NULL);
  500. if (lcremove == NULL)
  501. return (0);
  502. /* And add onto the next cell (from the original cell). */
  503. lcadd = TAILQ_NEXT(lc, entry);
  504. if (lcadd == NULL)
  505. return (0);
  506. /* Change the cells. */
  507. if (size > (u_int) -needed)
  508. size = -needed;
  509. layout_resize_adjust(lcadd, type, size);
  510. layout_resize_adjust(lcremove, type, -size);
  511. return (size);
  512. }
  513. /* Assign window pane to newly split cell. */
  514. void
  515. layout_assign_pane(struct layout_cell *lc, struct window_pane *wp)
  516. {
  517. layout_make_leaf(lc, wp);
  518. layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
  519. }
  520. /*
  521. * Split a pane into two. size is a hint, or -1 for default half/half
  522. * split. This must be followed by layout_assign_pane before much else happens!
  523. **/
  524. struct layout_cell *
  525. layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
  526. int insert_before)
  527. {
  528. struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
  529. u_int sx, sy, xoff, yoff, size1, size2;
  530. lc = wp->layout_cell;
  531. /* Copy the old cell size. */
  532. sx = lc->sx;
  533. sy = lc->sy;
  534. xoff = lc->xoff;
  535. yoff = lc->yoff;
  536. /* Check there is enough space for the two new panes. */
  537. switch (type) {
  538. case LAYOUT_LEFTRIGHT:
  539. if (sx < PANE_MINIMUM * 2 + 1)
  540. return (NULL);
  541. break;
  542. case LAYOUT_TOPBOTTOM:
  543. if (sy < PANE_MINIMUM * 2 + 1)
  544. return (NULL);
  545. break;
  546. default:
  547. fatalx("bad layout type");
  548. }
  549. if (lc->parent != NULL && lc->parent->type == type) {
  550. /*
  551. * If the parent exists and is of the same type as the split,
  552. * create a new cell and insert it after this one.
  553. */
  554. /* Create the new child cell. */
  555. lcparent = lc->parent;
  556. lcnew = layout_create_cell(lcparent);
  557. if (insert_before)
  558. TAILQ_INSERT_BEFORE(lc, lcnew, entry);
  559. else
  560. TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
  561. } else {
  562. /*
  563. * Otherwise create a new parent and insert it.
  564. */
  565. /* Create and insert the replacement parent. */
  566. lcparent = layout_create_cell(lc->parent);
  567. layout_make_node(lcparent, type);
  568. layout_set_size(lcparent, sx, sy, xoff, yoff);
  569. if (lc->parent == NULL)
  570. wp->window->layout_root = lcparent;
  571. else
  572. TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
  573. /* Insert the old cell. */
  574. lc->parent = lcparent;
  575. TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
  576. /* Create the new child cell. */
  577. lcnew = layout_create_cell(lcparent);
  578. if (insert_before)
  579. TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry);
  580. else
  581. TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
  582. }
  583. if (insert_before) {
  584. lc1 = lcnew;
  585. lc2 = lc;
  586. } else {
  587. lc1 = lc;
  588. lc2 = lcnew;
  589. }
  590. /* Set new cell sizes. size is the target size or -1 for middle split,
  591. * size1 is the size of the top/left and size2 the bottom/right.
  592. */
  593. switch (type) {
  594. case LAYOUT_LEFTRIGHT:
  595. if (size < 0)
  596. size2 = ((sx + 1) / 2) - 1;
  597. else if (insert_before)
  598. size2 = sx - size - 1;
  599. else
  600. size2 = size;
  601. if (size2 < PANE_MINIMUM)
  602. size2 = PANE_MINIMUM;
  603. else if (size2 > sx - 2)
  604. size2 = sx - 2;
  605. size1 = sx - 1 - size2;
  606. layout_set_size(lc1, size1, sy, xoff, yoff);
  607. layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
  608. break;
  609. case LAYOUT_TOPBOTTOM:
  610. if (size < 0)
  611. size2 = ((sy + 1) / 2) - 1;
  612. else if (insert_before)
  613. size2 = sy - size - 1;
  614. else
  615. size2 = size;
  616. if (size2 < PANE_MINIMUM)
  617. size2 = PANE_MINIMUM;
  618. else if (size2 > sy - 2)
  619. size2 = sy - 2;
  620. size1 = sy - 1 - size2;
  621. layout_set_size(lc1, sx, size1, xoff, yoff);
  622. layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
  623. break;
  624. default:
  625. fatalx("bad layout type");
  626. }
  627. /* Assign the panes. */
  628. layout_make_leaf(lc, wp);
  629. return (lcnew);
  630. }
  631. /* Destroy the cell associated with a pane. */
  632. void
  633. layout_close_pane(struct window_pane *wp)
  634. {
  635. /* Remove the cell. */
  636. layout_destroy_cell(wp->layout_cell, &wp->window->layout_root);
  637. /* Fix pane offsets and sizes. */
  638. if (wp->window->layout_root != NULL) {
  639. layout_fix_offsets(wp->window->layout_root);
  640. layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
  641. }
  642. notify_window_layout_changed(wp->window);
  643. }