1*eda6f593SDavid van Moolenbroek /* $Id: layout-custom.c,v 1.1.1.2 2011/08/17 18:40:04 jmmv Exp $ */ 2*eda6f593SDavid van Moolenbroek 3*eda6f593SDavid van Moolenbroek /* 4*eda6f593SDavid van Moolenbroek * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net> 5*eda6f593SDavid van Moolenbroek * 6*eda6f593SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any 7*eda6f593SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above 8*eda6f593SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies. 9*eda6f593SDavid van Moolenbroek * 10*eda6f593SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*eda6f593SDavid van Moolenbroek * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*eda6f593SDavid van Moolenbroek * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*eda6f593SDavid van Moolenbroek * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*eda6f593SDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15*eda6f593SDavid van Moolenbroek * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16*eda6f593SDavid van Moolenbroek * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*eda6f593SDavid van Moolenbroek */ 18*eda6f593SDavid van Moolenbroek 19*eda6f593SDavid van Moolenbroek #include <sys/types.h> 20*eda6f593SDavid van Moolenbroek 21*eda6f593SDavid van Moolenbroek #include <ctype.h> 22*eda6f593SDavid van Moolenbroek #include <string.h> 23*eda6f593SDavid van Moolenbroek 24*eda6f593SDavid van Moolenbroek #include "tmux.h" 25*eda6f593SDavid van Moolenbroek 26*eda6f593SDavid van Moolenbroek struct layout_cell *layout_find_bottomright(struct layout_cell *); 27*eda6f593SDavid van Moolenbroek u_short layout_checksum(const char *); 28*eda6f593SDavid van Moolenbroek int layout_append(struct layout_cell *, char *, size_t); 29*eda6f593SDavid van Moolenbroek struct layout_cell *layout_construct(struct layout_cell *, const char **); 30*eda6f593SDavid van Moolenbroek void layout_assign(struct window_pane **, struct layout_cell *); 31*eda6f593SDavid van Moolenbroek 32*eda6f593SDavid van Moolenbroek /* Find the bottom-right cell. */ 33*eda6f593SDavid van Moolenbroek struct layout_cell * 34*eda6f593SDavid van Moolenbroek layout_find_bottomright(struct layout_cell *lc) 35*eda6f593SDavid van Moolenbroek { 36*eda6f593SDavid van Moolenbroek if (lc->type == LAYOUT_WINDOWPANE) 37*eda6f593SDavid van Moolenbroek return (lc); 38*eda6f593SDavid van Moolenbroek lc = TAILQ_LAST(&lc->cells, layout_cells); 39*eda6f593SDavid van Moolenbroek return (layout_find_bottomright(lc)); 40*eda6f593SDavid van Moolenbroek } 41*eda6f593SDavid van Moolenbroek 42*eda6f593SDavid van Moolenbroek /* Calculate layout checksum. */ 43*eda6f593SDavid van Moolenbroek u_short 44*eda6f593SDavid van Moolenbroek layout_checksum(const char *layout) 45*eda6f593SDavid van Moolenbroek { 46*eda6f593SDavid van Moolenbroek u_short csum; 47*eda6f593SDavid van Moolenbroek 48*eda6f593SDavid van Moolenbroek csum = 0; 49*eda6f593SDavid van Moolenbroek for (; *layout != '\0'; layout++) { 50*eda6f593SDavid van Moolenbroek csum = (csum >> 1) + ((csum & 1) << 15); 51*eda6f593SDavid van Moolenbroek csum += *layout; 52*eda6f593SDavid van Moolenbroek } 53*eda6f593SDavid van Moolenbroek return (csum); 54*eda6f593SDavid van Moolenbroek } 55*eda6f593SDavid van Moolenbroek 56*eda6f593SDavid van Moolenbroek /* Dump layout as a string. */ 57*eda6f593SDavid van Moolenbroek char * 58*eda6f593SDavid van Moolenbroek layout_dump(struct window *w) 59*eda6f593SDavid van Moolenbroek { 60*eda6f593SDavid van Moolenbroek char layout[BUFSIZ], *out; 61*eda6f593SDavid van Moolenbroek 62*eda6f593SDavid van Moolenbroek *layout = '\0'; 63*eda6f593SDavid van Moolenbroek if (layout_append(w->layout_root, layout, sizeof layout) != 0) 64*eda6f593SDavid van Moolenbroek return (NULL); 65*eda6f593SDavid van Moolenbroek 66*eda6f593SDavid van Moolenbroek xasprintf(&out, "%4x,%s", layout_checksum(layout), layout); 67*eda6f593SDavid van Moolenbroek return (out); 68*eda6f593SDavid van Moolenbroek } 69*eda6f593SDavid van Moolenbroek 70*eda6f593SDavid van Moolenbroek /* Append information for a single cell. */ 71*eda6f593SDavid van Moolenbroek int 72*eda6f593SDavid van Moolenbroek layout_append(struct layout_cell *lc, char *buf, size_t len) 73*eda6f593SDavid van Moolenbroek { 74*eda6f593SDavid van Moolenbroek struct layout_cell *lcchild; 75*eda6f593SDavid van Moolenbroek char tmp[64]; 76*eda6f593SDavid van Moolenbroek size_t tmplen; 77*eda6f593SDavid van Moolenbroek const char *brackets = "]["; 78*eda6f593SDavid van Moolenbroek 79*eda6f593SDavid van Moolenbroek if (len == 0) 80*eda6f593SDavid van Moolenbroek return (-1); 81*eda6f593SDavid van Moolenbroek 82*eda6f593SDavid van Moolenbroek tmplen = xsnprintf(tmp, sizeof tmp, 83*eda6f593SDavid van Moolenbroek "%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff); 84*eda6f593SDavid van Moolenbroek if (tmplen > (sizeof tmp) - 1) 85*eda6f593SDavid van Moolenbroek return (-1); 86*eda6f593SDavid van Moolenbroek if (strlcat(buf, tmp, len) >= len) 87*eda6f593SDavid van Moolenbroek return (-1); 88*eda6f593SDavid van Moolenbroek 89*eda6f593SDavid van Moolenbroek switch (lc->type) { 90*eda6f593SDavid van Moolenbroek case LAYOUT_LEFTRIGHT: 91*eda6f593SDavid van Moolenbroek brackets = "}{"; 92*eda6f593SDavid van Moolenbroek /* FALLTHROUGH */ 93*eda6f593SDavid van Moolenbroek case LAYOUT_TOPBOTTOM: 94*eda6f593SDavid van Moolenbroek if (strlcat(buf, &brackets[1], len) >= len) 95*eda6f593SDavid van Moolenbroek return (-1); 96*eda6f593SDavid van Moolenbroek TAILQ_FOREACH(lcchild, &lc->cells, entry) { 97*eda6f593SDavid van Moolenbroek if (layout_append(lcchild, buf, len) != 0) 98*eda6f593SDavid van Moolenbroek return (-1); 99*eda6f593SDavid van Moolenbroek if (strlcat(buf, ",", len) >= len) 100*eda6f593SDavid van Moolenbroek return (-1); 101*eda6f593SDavid van Moolenbroek } 102*eda6f593SDavid van Moolenbroek buf[strlen(buf) - 1] = brackets[0]; 103*eda6f593SDavid van Moolenbroek break; 104*eda6f593SDavid van Moolenbroek case LAYOUT_WINDOWPANE: 105*eda6f593SDavid van Moolenbroek break; 106*eda6f593SDavid van Moolenbroek } 107*eda6f593SDavid van Moolenbroek 108*eda6f593SDavid van Moolenbroek return (0); 109*eda6f593SDavid van Moolenbroek } 110*eda6f593SDavid van Moolenbroek 111*eda6f593SDavid van Moolenbroek /* Parse a layout string and arrange window as layout. */ 112*eda6f593SDavid van Moolenbroek int 113*eda6f593SDavid van Moolenbroek layout_parse(struct window *w, const char *layout) 114*eda6f593SDavid van Moolenbroek { 115*eda6f593SDavid van Moolenbroek struct layout_cell *lc, *lcchild; 116*eda6f593SDavid van Moolenbroek struct window_pane *wp; 117*eda6f593SDavid van Moolenbroek u_int npanes, ncells, sx, sy; 118*eda6f593SDavid van Moolenbroek u_short csum; 119*eda6f593SDavid van Moolenbroek 120*eda6f593SDavid van Moolenbroek /* Check validity. */ 121*eda6f593SDavid van Moolenbroek if (sscanf(layout, "%hx,", &csum) != 1) 122*eda6f593SDavid van Moolenbroek return (-1); 123*eda6f593SDavid van Moolenbroek layout += 5; 124*eda6f593SDavid van Moolenbroek if (csum != layout_checksum(layout)) 125*eda6f593SDavid van Moolenbroek return (-1); 126*eda6f593SDavid van Moolenbroek 127*eda6f593SDavid van Moolenbroek /* Build the layout. */ 128*eda6f593SDavid van Moolenbroek lc = layout_construct(NULL, &layout); 129*eda6f593SDavid van Moolenbroek if (lc == NULL) 130*eda6f593SDavid van Moolenbroek return (-1); 131*eda6f593SDavid van Moolenbroek if (*layout != '\0') 132*eda6f593SDavid van Moolenbroek goto fail; 133*eda6f593SDavid van Moolenbroek 134*eda6f593SDavid van Moolenbroek /* Check this window will fit into the layout. */ 135*eda6f593SDavid van Moolenbroek for (;;) { 136*eda6f593SDavid van Moolenbroek npanes = window_count_panes(w); 137*eda6f593SDavid van Moolenbroek ncells = layout_count_cells(lc); 138*eda6f593SDavid van Moolenbroek if (npanes > ncells) 139*eda6f593SDavid van Moolenbroek goto fail; 140*eda6f593SDavid van Moolenbroek if (npanes == ncells) 141*eda6f593SDavid van Moolenbroek break; 142*eda6f593SDavid van Moolenbroek 143*eda6f593SDavid van Moolenbroek /* Fewer panes than cells - close the bottom right. */ 144*eda6f593SDavid van Moolenbroek lcchild = layout_find_bottomright(lc); 145*eda6f593SDavid van Moolenbroek layout_destroy_cell(lcchild, &lc); 146*eda6f593SDavid van Moolenbroek } 147*eda6f593SDavid van Moolenbroek 148*eda6f593SDavid van Moolenbroek /* Save the old window size and resize to the layout size. */ 149*eda6f593SDavid van Moolenbroek sx = w->sx; sy = w->sy; 150*eda6f593SDavid van Moolenbroek window_resize(w, lc->sx, lc->sy); 151*eda6f593SDavid van Moolenbroek 152*eda6f593SDavid van Moolenbroek /* Destroy the old layout and swap to the new. */ 153*eda6f593SDavid van Moolenbroek layout_free_cell(w->layout_root); 154*eda6f593SDavid van Moolenbroek w->layout_root = lc; 155*eda6f593SDavid van Moolenbroek 156*eda6f593SDavid van Moolenbroek /* Assign the panes into the cells. */ 157*eda6f593SDavid van Moolenbroek wp = TAILQ_FIRST(&w->panes); 158*eda6f593SDavid van Moolenbroek layout_assign(&wp, lc); 159*eda6f593SDavid van Moolenbroek 160*eda6f593SDavid van Moolenbroek /* Update pane offsets and sizes. */ 161*eda6f593SDavid van Moolenbroek layout_fix_offsets(lc); 162*eda6f593SDavid van Moolenbroek layout_fix_panes(w, lc->sx, lc->sy); 163*eda6f593SDavid van Moolenbroek 164*eda6f593SDavid van Moolenbroek /* Then resize the layout back to the original window size. */ 165*eda6f593SDavid van Moolenbroek layout_resize(w, sx, sy); 166*eda6f593SDavid van Moolenbroek window_resize(w, sx, sy); 167*eda6f593SDavid van Moolenbroek 168*eda6f593SDavid van Moolenbroek layout_print_cell(lc, __func__, 0); 169*eda6f593SDavid van Moolenbroek 170*eda6f593SDavid van Moolenbroek return (0); 171*eda6f593SDavid van Moolenbroek 172*eda6f593SDavid van Moolenbroek fail: 173*eda6f593SDavid van Moolenbroek layout_free_cell(lc); 174*eda6f593SDavid van Moolenbroek return (-1); 175*eda6f593SDavid van Moolenbroek } 176*eda6f593SDavid van Moolenbroek 177*eda6f593SDavid van Moolenbroek /* Assign panes into cells. */ 178*eda6f593SDavid van Moolenbroek void 179*eda6f593SDavid van Moolenbroek layout_assign(struct window_pane **wp, struct layout_cell *lc) 180*eda6f593SDavid van Moolenbroek { 181*eda6f593SDavid van Moolenbroek struct layout_cell *lcchild; 182*eda6f593SDavid van Moolenbroek 183*eda6f593SDavid van Moolenbroek switch (lc->type) { 184*eda6f593SDavid van Moolenbroek case LAYOUT_WINDOWPANE: 185*eda6f593SDavid van Moolenbroek layout_make_leaf(lc, *wp); 186*eda6f593SDavid van Moolenbroek *wp = TAILQ_NEXT(*wp, entry); 187*eda6f593SDavid van Moolenbroek return; 188*eda6f593SDavid van Moolenbroek case LAYOUT_LEFTRIGHT: 189*eda6f593SDavid van Moolenbroek case LAYOUT_TOPBOTTOM: 190*eda6f593SDavid van Moolenbroek TAILQ_FOREACH(lcchild, &lc->cells, entry) 191*eda6f593SDavid van Moolenbroek layout_assign(wp, lcchild); 192*eda6f593SDavid van Moolenbroek return; 193*eda6f593SDavid van Moolenbroek } 194*eda6f593SDavid van Moolenbroek } 195*eda6f593SDavid van Moolenbroek 196*eda6f593SDavid van Moolenbroek /* Construct a cell from all or part of a layout tree. */ 197*eda6f593SDavid van Moolenbroek struct layout_cell * 198*eda6f593SDavid van Moolenbroek layout_construct(struct layout_cell *lcparent, const char **layout) 199*eda6f593SDavid van Moolenbroek { 200*eda6f593SDavid van Moolenbroek struct layout_cell *lc, *lcchild; 201*eda6f593SDavid van Moolenbroek u_int sx, sy, xoff, yoff; 202*eda6f593SDavid van Moolenbroek 203*eda6f593SDavid van Moolenbroek if (!isdigit((u_char) **layout)) 204*eda6f593SDavid van Moolenbroek return (NULL); 205*eda6f593SDavid van Moolenbroek if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4) 206*eda6f593SDavid van Moolenbroek return (NULL); 207*eda6f593SDavid van Moolenbroek 208*eda6f593SDavid van Moolenbroek while (isdigit((u_char) **layout)) 209*eda6f593SDavid van Moolenbroek (*layout)++; 210*eda6f593SDavid van Moolenbroek if (**layout != 'x') 211*eda6f593SDavid van Moolenbroek return (NULL); 212*eda6f593SDavid van Moolenbroek (*layout)++; 213*eda6f593SDavid van Moolenbroek while (isdigit((u_char) **layout)) 214*eda6f593SDavid van Moolenbroek (*layout)++; 215*eda6f593SDavid van Moolenbroek if (**layout != ',') 216*eda6f593SDavid van Moolenbroek return (NULL); 217*eda6f593SDavid van Moolenbroek (*layout)++; 218*eda6f593SDavid van Moolenbroek while (isdigit((u_char) **layout)) 219*eda6f593SDavid van Moolenbroek (*layout)++; 220*eda6f593SDavid van Moolenbroek if (**layout != ',') 221*eda6f593SDavid van Moolenbroek return (NULL); 222*eda6f593SDavid van Moolenbroek (*layout)++; 223*eda6f593SDavid van Moolenbroek while (isdigit((u_char) **layout)) 224*eda6f593SDavid van Moolenbroek (*layout)++; 225*eda6f593SDavid van Moolenbroek 226*eda6f593SDavid van Moolenbroek lc = layout_create_cell(lcparent); 227*eda6f593SDavid van Moolenbroek lc->sx = sx; 228*eda6f593SDavid van Moolenbroek lc->sy = sy; 229*eda6f593SDavid van Moolenbroek lc->xoff = xoff; 230*eda6f593SDavid van Moolenbroek lc->yoff = yoff; 231*eda6f593SDavid van Moolenbroek 232*eda6f593SDavid van Moolenbroek switch (**layout) { 233*eda6f593SDavid van Moolenbroek case ',': 234*eda6f593SDavid van Moolenbroek case '}': 235*eda6f593SDavid van Moolenbroek case ']': 236*eda6f593SDavid van Moolenbroek case '\0': 237*eda6f593SDavid van Moolenbroek return (lc); 238*eda6f593SDavid van Moolenbroek case '{': 239*eda6f593SDavid van Moolenbroek lc->type = LAYOUT_LEFTRIGHT; 240*eda6f593SDavid van Moolenbroek break; 241*eda6f593SDavid van Moolenbroek case '[': 242*eda6f593SDavid van Moolenbroek lc->type = LAYOUT_TOPBOTTOM; 243*eda6f593SDavid van Moolenbroek break; 244*eda6f593SDavid van Moolenbroek default: 245*eda6f593SDavid van Moolenbroek goto fail; 246*eda6f593SDavid van Moolenbroek } 247*eda6f593SDavid van Moolenbroek 248*eda6f593SDavid van Moolenbroek do { 249*eda6f593SDavid van Moolenbroek (*layout)++; 250*eda6f593SDavid van Moolenbroek lcchild = layout_construct(lc, layout); 251*eda6f593SDavid van Moolenbroek if (lcchild == NULL) 252*eda6f593SDavid van Moolenbroek goto fail; 253*eda6f593SDavid van Moolenbroek TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry); 254*eda6f593SDavid van Moolenbroek } while (**layout == ','); 255*eda6f593SDavid van Moolenbroek 256*eda6f593SDavid van Moolenbroek switch (lc->type) { 257*eda6f593SDavid van Moolenbroek case LAYOUT_LEFTRIGHT: 258*eda6f593SDavid van Moolenbroek if (**layout != '}') 259*eda6f593SDavid van Moolenbroek goto fail; 260*eda6f593SDavid van Moolenbroek break; 261*eda6f593SDavid van Moolenbroek case LAYOUT_TOPBOTTOM: 262*eda6f593SDavid van Moolenbroek if (**layout != ']') 263*eda6f593SDavid van Moolenbroek goto fail; 264*eda6f593SDavid van Moolenbroek break; 265*eda6f593SDavid van Moolenbroek default: 266*eda6f593SDavid van Moolenbroek goto fail; 267*eda6f593SDavid van Moolenbroek } 268*eda6f593SDavid van Moolenbroek (*layout)++; 269*eda6f593SDavid van Moolenbroek 270*eda6f593SDavid van Moolenbroek return (lc); 271*eda6f593SDavid van Moolenbroek 272*eda6f593SDavid van Moolenbroek fail: 273*eda6f593SDavid van Moolenbroek layout_free_cell(lc); 274*eda6f593SDavid van Moolenbroek return (NULL); 275*eda6f593SDavid van Moolenbroek } 276