123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739 |
- #include <sys/types.h>
- #include <stdlib.h>
- #include "tmux.h"
- int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int);
- int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int);
- struct layout_cell *
- layout_create_cell(struct layout_cell *lcparent)
- {
- struct layout_cell *lc;
- lc = xmalloc(sizeof *lc);
- lc->type = LAYOUT_WINDOWPANE;
- lc->parent = lcparent;
- TAILQ_INIT(&lc->cells);
- lc->sx = UINT_MAX;
- lc->sy = UINT_MAX;
- lc->xoff = UINT_MAX;
- lc->yoff = UINT_MAX;
- lc->wp = NULL;
- return (lc);
- }
- void
- layout_free_cell(struct layout_cell *lc)
- {
- struct layout_cell *lcchild;
- switch (lc->type) {
- case LAYOUT_LEFTRIGHT:
- case LAYOUT_TOPBOTTOM:
- while (!TAILQ_EMPTY(&lc->cells)) {
- lcchild = TAILQ_FIRST(&lc->cells);
- TAILQ_REMOVE(&lc->cells, lcchild, entry);
- layout_free_cell(lcchild);
- }
- break;
- case LAYOUT_WINDOWPANE:
- if (lc->wp != NULL)
- lc->wp->layout_cell = NULL;
- break;
- }
- free(lc);
- }
- void
- layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
- {
- struct layout_cell *lcchild;
- log_debug("%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n,
- " ", lc, lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
- lc->sy);
- switch (lc->type) {
- case LAYOUT_LEFTRIGHT:
- case LAYOUT_TOPBOTTOM:
- TAILQ_FOREACH(lcchild, &lc->cells, entry)
- layout_print_cell(lcchild, hdr, n + 1);
- break;
- case LAYOUT_WINDOWPANE:
- break;
- }
- }
- void
- layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
- u_int yoff)
- {
- lc->sx = sx;
- lc->sy = sy;
- lc->xoff = xoff;
- lc->yoff = yoff;
- }
- void
- layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
- {
- lc->type = LAYOUT_WINDOWPANE;
- TAILQ_INIT(&lc->cells);
- wp->layout_cell = lc;
- lc->wp = wp;
- }
- void
- layout_make_node(struct layout_cell *lc, enum layout_type type)
- {
- if (type == LAYOUT_WINDOWPANE)
- fatalx("bad layout type");
- lc->type = type;
- TAILQ_INIT(&lc->cells);
- if (lc->wp != NULL)
- lc->wp->layout_cell = NULL;
- lc->wp = NULL;
- }
- void
- layout_fix_offsets(struct layout_cell *lc)
- {
- struct layout_cell *lcchild;
- u_int xoff, yoff;
- if (lc->type == LAYOUT_LEFTRIGHT) {
- xoff = lc->xoff;
- TAILQ_FOREACH(lcchild, &lc->cells, entry) {
- lcchild->xoff = xoff;
- lcchild->yoff = lc->yoff;
- if (lcchild->type != LAYOUT_WINDOWPANE)
- layout_fix_offsets(lcchild);
- xoff += lcchild->sx + 1;
- }
- } else {
- yoff = lc->yoff;
- TAILQ_FOREACH(lcchild, &lc->cells, entry) {
- lcchild->xoff = lc->xoff;
- lcchild->yoff = yoff;
- if (lcchild->type != LAYOUT_WINDOWPANE)
- layout_fix_offsets(lcchild);
- yoff += lcchild->sy + 1;
- }
- }
- }
- void
- layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
- {
- struct window_pane *wp;
- struct layout_cell *lc;
- u_int sx, sy;
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if ((lc = wp->layout_cell) == NULL)
- continue;
- wp->xoff = lc->xoff;
- wp->yoff = lc->yoff;
-
-
- if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx)
- sx = lc->sx;
- else {
- sx = wsx - lc->xoff;
- if (sx < 1)
- sx = lc->sx;
- }
-
- if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy)
- sy = lc->sy;
- else {
- sy = wsy - lc->yoff;
- if (sy < 2)
- sy = lc->sy;
- }
- window_pane_resize(wp, sx, sy);
- }
- }
- u_int
- layout_count_cells(struct layout_cell *lc)
- {
- struct layout_cell *lcchild;
- u_int n;
- switch (lc->type) {
- case LAYOUT_WINDOWPANE:
- return (1);
- case LAYOUT_LEFTRIGHT:
- case LAYOUT_TOPBOTTOM:
- n = 0;
- TAILQ_FOREACH(lcchild, &lc->cells, entry)
- n += layout_count_cells(lcchild);
- return (n);
- default:
- fatalx("bad layout type");
- }
- }
- u_int
- layout_resize_check(struct layout_cell *lc, enum layout_type type)
- {
- struct layout_cell *lcchild;
- u_int available, minimum;
- if (lc->type == LAYOUT_WINDOWPANE) {
-
- if (type == LAYOUT_LEFTRIGHT)
- available = lc->sx;
- else
- available = lc->sy;
- if (available > PANE_MINIMUM)
- available -= PANE_MINIMUM;
- else
- available = 0;
- } else if (lc->type == type) {
-
- available = 0;
- TAILQ_FOREACH(lcchild, &lc->cells, entry)
- available += layout_resize_check(lcchild, type);
- } else {
-
- minimum = UINT_MAX;
- TAILQ_FOREACH(lcchild, &lc->cells, entry) {
- available = layout_resize_check(lcchild, type);
- if (available < minimum)
- minimum = available;
- }
- available = minimum;
- }
- return (available);
- }
- void
- layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
- {
- struct layout_cell *lcchild;
-
- if (type == LAYOUT_LEFTRIGHT)
- lc->sx += change;
- else
- lc->sy += change;
-
- if (type == LAYOUT_WINDOWPANE)
- return;
-
- if (lc->type != type) {
- TAILQ_FOREACH(lcchild, &lc->cells, entry)
- layout_resize_adjust(lcchild, type, change);
- return;
- }
-
- while (change != 0) {
- TAILQ_FOREACH(lcchild, &lc->cells, entry) {
- if (change == 0)
- break;
- if (change > 0) {
- layout_resize_adjust(lcchild, type, 1);
- change--;
- continue;
- }
- if (layout_resize_check(lcchild, type) > 0) {
- layout_resize_adjust(lcchild, type, -1);
- change++;
- }
- }
- }
- }
- void
- layout_destroy_cell(struct layout_cell *lc, struct layout_cell **lcroot)
- {
- struct layout_cell *lcother, *lcparent;
-
- lcparent = lc->parent;
- if (lcparent == NULL) {
- layout_free_cell(lc);
- *lcroot = NULL;
- return;
- }
-
- if (lc == TAILQ_FIRST(&lcparent->cells))
- lcother = TAILQ_NEXT(lc, entry);
- else
- lcother = TAILQ_PREV(lc, layout_cells, entry);
- if (lcparent->type == LAYOUT_LEFTRIGHT)
- layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
- else
- layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
-
- TAILQ_REMOVE(&lcparent->cells, lc, entry);
- layout_free_cell(lc);
-
- lc = TAILQ_FIRST(&lcparent->cells);
- if (TAILQ_NEXT(lc, entry) == NULL) {
- TAILQ_REMOVE(&lcparent->cells, lc, entry);
- lc->parent = lcparent->parent;
- if (lc->parent == NULL) {
- lc->xoff = 0; lc->yoff = 0;
- *lcroot = lc;
- } else
- TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
- layout_free_cell(lcparent);
- }
- }
- void
- layout_init(struct window *w, struct window_pane *wp)
- {
- struct layout_cell *lc;
- lc = w->layout_root = layout_create_cell(NULL);
- layout_set_size(lc, w->sx, w->sy, 0, 0);
- layout_make_leaf(lc, wp);
- layout_fix_panes(w, w->sx, w->sy);
- }
- void
- layout_free(struct window *w)
- {
- layout_free_cell(w->layout_root);
- }
- void
- layout_resize(struct window *w, u_int sx, u_int sy)
- {
- struct layout_cell *lc = w->layout_root;
- int xlimit, ylimit, xchange, ychange;
-
- xchange = sx - w->sx;
- xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT);
- if (xchange < 0 && xchange < -xlimit)
- xchange = -xlimit;
- if (xlimit == 0) {
- if (sx <= lc->sx)
- xchange = 0;
- else
- xchange = sx - lc->sx;
- }
- if (xchange != 0)
- layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange);
-
- ychange = sy - w->sy;
- ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM);
- if (ychange < 0 && ychange < -ylimit)
- ychange = -ylimit;
- if (ylimit == 0) {
- if (sy <= lc->sy)
- ychange = 0;
- else
- ychange = sy - lc->sy;
- }
- if (ychange != 0)
- layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange);
-
- layout_fix_offsets(lc);
- layout_fix_panes(w, sx, sy);
- }
- void
- layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
- u_int new_size)
- {
- struct layout_cell *lc, *lcparent;
- int change, size;
- lc = wp->layout_cell;
-
- lcparent = lc->parent;
- while (lcparent != NULL && lcparent->type != type) {
- lc = lcparent;
- lcparent = lc->parent;
- }
- if (lcparent == NULL)
- return;
-
- if (type == LAYOUT_LEFTRIGHT)
- size = lc->sx;
- else
- size = lc->sy;
- if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
- change = size - new_size;
- else
- change = new_size - size;
-
- layout_resize_pane(wp, type, change);
- }
- void
- layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
- {
- struct layout_cell *lc, *lcparent;
- int needed, size;
- lc = wp->layout_cell;
-
- lcparent = lc->parent;
- while (lcparent != NULL && lcparent->type != type) {
- lc = lcparent;
- lcparent = lc->parent;
- }
- if (lcparent == NULL)
- return;
-
- if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
- lc = TAILQ_PREV(lc, layout_cells, entry);
-
- needed = change;
- while (needed != 0) {
- if (change > 0) {
- size = layout_resize_pane_grow(lc, type, needed);
- needed -= size;
- } else {
- size = layout_resize_pane_shrink(lc, type, needed);
- needed += size;
- }
- if (size == 0)
- break;
- }
-
- layout_fix_offsets(wp->window->layout_root);
- layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
- notify_window_layout_changed(wp->window);
- }
- int
- layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
- int needed)
- {
- struct layout_cell *lcadd, *lcremove;
- u_int size;
-
- lcadd = lc;
-
- lcremove = TAILQ_NEXT(lc, entry);
- while (lcremove != NULL) {
- size = layout_resize_check(lcremove, type);
- if (size > 0)
- break;
- lcremove = TAILQ_NEXT(lcremove, entry);
- }
-
- if (lcremove == NULL) {
- lcremove = TAILQ_PREV(lc, layout_cells, entry);
- while (lcremove != NULL) {
- size = layout_resize_check(lcremove, type);
- if (size > 0)
- break;
- lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
- }
- if (lcremove == NULL)
- return (0);
- }
-
- if (size > (u_int) needed)
- size = needed;
- layout_resize_adjust(lcadd, type, size);
- layout_resize_adjust(lcremove, type, -size);
- return (size);
- }
- int
- layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
- int needed)
- {
- struct layout_cell *lcadd, *lcremove;
- u_int size;
-
- lcremove = lc;
- do {
- size = layout_resize_check(lcremove, type);
- if (size != 0)
- break;
- lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
- } while (lcremove != NULL);
- if (lcremove == NULL)
- return (0);
-
- lcadd = TAILQ_NEXT(lc, entry);
- if (lcadd == NULL)
- return (0);
-
- if (size > (u_int) -needed)
- size = -needed;
- layout_resize_adjust(lcadd, type, size);
- layout_resize_adjust(lcremove, type, -size);
- return (size);
- }
- void
- layout_assign_pane(struct layout_cell *lc, struct window_pane *wp)
- {
- layout_make_leaf(lc, wp);
- layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
- }
- struct layout_cell *
- layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
- int insert_before)
- {
- struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
- u_int sx, sy, xoff, yoff, size1, size2;
- lc = wp->layout_cell;
-
- sx = lc->sx;
- sy = lc->sy;
- xoff = lc->xoff;
- yoff = lc->yoff;
-
- switch (type) {
- case LAYOUT_LEFTRIGHT:
- if (sx < PANE_MINIMUM * 2 + 1)
- return (NULL);
- break;
- case LAYOUT_TOPBOTTOM:
- if (sy < PANE_MINIMUM * 2 + 1)
- return (NULL);
- break;
- default:
- fatalx("bad layout type");
- }
- if (lc->parent != NULL && lc->parent->type == type) {
-
-
- lcparent = lc->parent;
- lcnew = layout_create_cell(lcparent);
- if (insert_before)
- TAILQ_INSERT_BEFORE(lc, lcnew, entry);
- else
- TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
- } else {
-
-
- lcparent = layout_create_cell(lc->parent);
- layout_make_node(lcparent, type);
- layout_set_size(lcparent, sx, sy, xoff, yoff);
- if (lc->parent == NULL)
- wp->window->layout_root = lcparent;
- else
- TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
-
- lc->parent = lcparent;
- TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
-
- lcnew = layout_create_cell(lcparent);
- if (insert_before)
- TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry);
- else
- TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
- }
- if (insert_before) {
- lc1 = lcnew;
- lc2 = lc;
- } else {
- lc1 = lc;
- lc2 = lcnew;
- }
-
- switch (type) {
- case LAYOUT_LEFTRIGHT:
- if (size < 0)
- size2 = ((sx + 1) / 2) - 1;
- else if (insert_before)
- size2 = sx - size - 1;
- else
- size2 = size;
- if (size2 < PANE_MINIMUM)
- size2 = PANE_MINIMUM;
- else if (size2 > sx - 2)
- size2 = sx - 2;
- size1 = sx - 1 - size2;
- layout_set_size(lc1, size1, sy, xoff, yoff);
- layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
- break;
- case LAYOUT_TOPBOTTOM:
- if (size < 0)
- size2 = ((sy + 1) / 2) - 1;
- else if (insert_before)
- size2 = sy - size - 1;
- else
- size2 = size;
- if (size2 < PANE_MINIMUM)
- size2 = PANE_MINIMUM;
- else if (size2 > sy - 2)
- size2 = sy - 2;
- size1 = sy - 1 - size2;
- layout_set_size(lc1, sx, size1, xoff, yoff);
- layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
- break;
- default:
- fatalx("bad layout type");
- }
-
- layout_make_leaf(lc, wp);
- return (lcnew);
- }
- void
- layout_close_pane(struct window_pane *wp)
- {
-
- layout_destroy_cell(wp->layout_cell, &wp->window->layout_root);
-
- if (wp->window->layout_root != NULL) {
- layout_fix_offsets(wp->window->layout_root);
- layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
- }
- notify_window_layout_changed(wp->window);
- }
|